Skip to content

rodezee/mdx-gun-inline

Repository files navigation

🔫 mdx-gun

A lightweight web component that fires MDX (Markdown + JSX) code reactively. Perfect for interactive documentation, dynamic content, and reactive interfaces.

Features:

  • Reactive: Responds to URL hash changes
  • 📝 MDX Support: Full Markdown + JSX syntax
  • 🎮 Three Trigger Modes: Hash-based, auto-fire attribute, or manual
  • 🔒 Safe Execution: Isolated Shadow DOM execution
  • 🎯 Vanilla JS: Framework-agnostic, zero dependencies* web component
  • 📦 Lightweight: Only ~5KB minified, only @mdx-js/mdx dependency

*Only requires @mdx-js/mdx for compilation

Installation

npm install mdx-gun @mdx-js/mdx

Quick Start

1. Auto-Fire on Load

<mdx-gun fire>
# Hello World!

This content fires **automatically** when the page loads.
</mdx-gun>

2. Hash-Based Navigation

<!-- Navigation links -->
<a href="#about">About</a>
<a href="#features">Features</a>

<!-- Sections triggered by hash -->
<mdx-gun id="about">
## About
Content shown when URL is #about
</mdx-gun>

<mdx-gun id="features">
## Features
Content shown when URL is #features
</mdx-gun>

3. Manual Trigger (JavaScript)

<mdx-gun id="dynamic"></mdx-gun>

<script>
  const gun = document.getElementById('dynamic');
  const mdxCode = `
# Generated Content

This was created **dynamically** at ${new Date().toLocaleTimeString()}
  `;
  
  await gun.execute(mdxCode);
</script>

API Reference

HTML Attributes

Attribute Type Description
id string Identifier for hash-based triggering
fire boolean Auto-execute on component load
mdx-code string MDX code to render

JavaScript API

fire(): Promise<void>

Manually execute the MDX code.

const gun = document.querySelector('mdx-gun');
await gun.fire();

execute(mdxCode: string): Promise<void>

Execute custom MDX code dynamically.

await gun.execute('# Dynamic Content\n\nCreated at ' + new Date());

setComponents(components: Record<string, any>): void

Inject custom React components for use in MDX.

const gun = document.querySelector('mdx-gun');
gun.setComponents({
  Alert: ({ children }) => `<div class="alert">${children}</div>`,
  Button: ({ label }) => `<button>${label}</button>`,
});

await gun.execute(`
<Alert>
  <Button label="Click me" />
</Alert>
`);

setScope(scope: Record<string, any>): void

Provide variables accessible in the MDX context.

const gun = document.querySelector('mdx-gun');
gun.setScope({
  username: 'Alice',
  isDarkMode: true,
  items: ['Item 1', 'Item 2', 'Item 3'],
});

await gun.execute(`
# Welcome, \${scope.username}!

Theme: \${scope.isDarkMode ? '🌙 Dark' : '☀️ Light'}
`);

Events

mdx-executed

Fired when MDX code is successfully compiled and executed.

gun.addEventListener('mdx-executed', (event) => {
  console.log('MDX executed with result:', event.detail.result);
  console.log('Execution context:', event.detail.context);
});

mdx-error

Fired when an error occurs during compilation or execution.

gun.addEventListener('mdx-error', (event) => {
  console.error('MDX Error:', event.detail.error);
});

Advanced Examples

Interactive Documentation

<mdx-gun id="api-docs" fire>
# API Documentation

## Endpoints

- `GET /api/users` - List all users
- `POST /api/users` - Create a new user
- `PUT /api/users/:id` - Update user
- `DELETE /api/users/:id` - Delete user

## Example Response

\`\`\`json
{
  "id": 1,
  "name": "John Doe",
  "email": "john@example.com"
}
\`\`\`
</mdx-gun>

Dynamic Form Generation

<mdx-gun id="form-generator"></mdx-gun>

<script>
  const gun = document.getElementById('form-generator');
  
  gun.setScope({
    fields: [
      { name: 'Name', type: 'text' },
      { name: 'Email', type: 'email' },
      { name: 'Message', type: 'textarea' },
    ]
  });

  const mdxCode = `
# Contact Form

\${scope.fields.map(field => 
  \`<label>\${field.name}</label>
   <input type="\${field.type}" name="\${field.name.toLowerCase()}" />\`
).join('')}

<button type="submit">Send</button>
  `;

  await gun.execute(mdxCode);
</script>

Interactive Content with State

<mdx-gun fire id="counter"></mdx-gun>

<script>
  const gun = document.getElementById('counter');
  let count = 0;

  gun.setScope({
    count: count,
    increment: () => {
      count++;
      renderCounter();
    },
  });

  async function renderCounter() {
    const mdxCode = `
# Counter: ${count}

<button onclick="window.incrementCounter()">+1</button>

Current value: **${count}**
    `;
    await gun.execute(mdxCode);
  }

  window.incrementCounter = gun.scope.increment;
  renderCounter();
</script>

Use Cases

  • 📚 Interactive Docs: Create dynamic documentation that responds to navigation
  • 🎓 Educational Content: Build interactive tutorials with executable examples
  • 🎨 Design Systems: Showcase components and patterns dynamically
  • 📊 Dashboards: Render dynamic content based on user interactions
  • 🔍 Live Previews: Preview markdown/MDX in real-time
  • 🌐 In-App Documentation: Embed help content that updates dynamically

Development

Setup

npm install
npm run dev      # Start dev server
npm run build    # Build for production
npm run test     # Run tests
npm run preview  # Preview production build

Project Structure

mdx-gun/
├── src/
│   ├── index.ts           # Main web component
│   └── index.test.ts      # Tests
├── examples/
│   └── index.html         # Demo page
├── dist/                  # Built files (generated)
├── vite.config.ts         # Build configuration
├── tsconfig.json          # TypeScript config
└── package.json           # Dependencies

Browser Support

  • Chrome/Chromium: ✅
  • Firefox: ✅
  • Safari: ✅
  • Edge: ✅
  • Requires: ES2020, Web Components, Shadow DOM

Performance Considerations

  • MDX compilation happens once and is cached
  • Use setScope() for dynamic data updates
  • Avoid re-rendering large components frequently
  • Consider lazy-loading for large MDX files

Security

  • MDX code is evaluated in a controlled context
  • Always validate user-provided MDX content
  • Custom components should be carefully reviewed
  • Never execute untrusted MDX code in high-security contexts

Contributing

Contributions are welcome! Please:

  1. Fork the repository
  2. Create a feature branch
  3. Add tests for new features
  4. Submit a pull request

License

MIT © 2026

Inspiration

This project brings the power of MDX to interactive web experiences, combining:

  • Markdown's simplicity
  • JSX's expressiveness
  • Web Components' encapsulation
  • Reactive paradigms for dynamic content

Perfect for developers who love writing in markdown but need the power of JavaScript!


Did you find this useful? Leave a ⭐ on GitHub!

About

No description, website, or topics provided.

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages