zero-md

repository·main·Indexed 20 days ago

https://github.com/zerodevx/zero-md

A lightweight, zero-config web component that renders Markdown as HTML within a Shadow DOM. It supports math rendering via KaTeX, diagrams via Mermaid, and syntax highlighting via highlight.js. The component can be integrated via CDN or npm and supports external files via the src attribute or inline markdown using script tags. It includes built-in light and dark themes and is extensible through subclassing.

Tokens
16.8K
Snippets
58
Records
68
Agent score
66%

What's inside zero-md

  1. What is <zero-md>?

    main

    <zero-md> is a zero-config markdown-to-html web component designed to load and display external Markdown files. It is built on the Custom Elements V1 specification and uses Marked for transformation and Prism for syntax highlighting. The component renders content into its own self-contained shadow DOM container.

    Key Features:

    • Automated hash-link scrolls.
    • Built-in FOUC (Flash of Unstyled Content) prevention.
    • Automatic URL rewriting relative to the src attribute.
    • Automatic re-rendering when the src attribute or inline markdown/style templates change.
    • Support for >200 code languages with automatic detection.
    • Easy styling mechanism and high extensibility.

    Important Security Note: Markdown files must be hosted on a web server. Due to browser security restrictions, you cannot access local files directly via the file system. Standard CORS (Cross-Origin Resource Sharing) rules apply when loading files from different domains.

  2. Overview of zero-md

    main

    zero-md is a zero-config web component that converts Markdown into HTML. It is built on the Custom Elements V1 specification and renders content inside a self-contained Shadow DOM container.

    Key features include:

    • Math rendering: via KaTeX
    • Diagrams: via Mermaid
    • Syntax highlighting: with auto-language detection (using highlight.js)
    • Navigation: Hash-link scroll handling for anchor navigation
    • UX: FOUC (Flash of Unstyled Content) prevention and auto re-rendering when inputs or attributes change
    • Theming: Built-in light and dark themes
    • Extensibility: Spec-compliant extensibility

    Important Security Note: Markdown files must be served over HTTP/HTTPS. Browsers restrict local file access (file:// protocol) due to security policies, and standard CORS rules apply.

  3. Extend zero-md by subclassing ZeroMd

    main
    You can extend the component's functionality by creating a subclass of ZeroMd. This follows the standard Custom Elements V1 specification. Use the load() method to configure defaults or the parse() method to process the markdown-to-HTML conversion.
  4. Render math with KaTeX

    main

    zero-md supports LaTeX syntax for mathematical equations via KaTeX. It supports three formats:

    1. Inline Math: Use single dollar signs $ ... $.
    2. Block-level Math: Use double dollar signs $$ ... $$.
    3. Math Code Block: Use a ```math fenced code block.
    // Inline
    $\sqrt{3x-1}+(1+x)^2$
    
    // Block
    $$
    $\sqrt{3x-1}+(1+x)^2$
    $$
    
    // Code Block
    ```math
    $\sqrt{3x-1}+(1+x)^2$
  5. Understand Markdown source priority and fallback behavior

    main

    In V2 and later, the behavior of the src attribute relative to inline content has changed. The <script type="text/markdown"> content should be treated as a "fallback".

    If the src attribute resolves to a valid file, that file's content will be rendered. The inline <script> content will only be rendered if the src attribute is falsy (e.g., empty or missing).

    <!-- The script content will NOT be rendered because src is present and valid -->
    <zero-md src="will-render.md">
      <script type="text/markdown">
        # This will NOT be rendered
      </script>
    </zero-md>
    
    <!-- The script content WILL be rendered because src is falsy -->
    <zero-md src="">
      <script type="text/markdown">
        # This WILL be rendered
      </script>
    </zero-md>
  6. Register zero-md via CDN

    main

    In v3, the custom element is not automatically registered by default when loading via a script tag. To automatically register the zero-md custom element, append the ?register query parameter to the CDN URL.

    https://cdn.jsdelivr.net/npm/zero-md@3?register
  7. Install zero-md in web projects via npm

    main

    To use zero-md in a modern web project with a bundler (like Webpack, Rollup, or Vite), install the package via npm. You must then import the ZeroMd class and register it with the customElements API before using the tag.

    $ npm install --save zero-md
    // Import the element definition
    import ZeroMd from 'zero-md'
    
    // Register the custom element
    customElements.define('zero-md', ZeroMd)
    
    // Use the element in your application
    app.render(`<zero-md src=${src}></zero-md>`, target)
  8. Configure global defaults using the load() function

    main

    The load() function runs once when the element is created. It is the ideal place to configure global settings for all instances of your custom element.

    Override default style template

    Set this.template to provide custom CSS or external stylesheets.

    Set themes globally

    Use STYLES.preset('light') or STYLES.preset('dark') to force a theme.

    Set default attributes

    Use this.setAttribute() to apply attributes like no-auto or no-shadow to all instances.

    Add marked extensions

    Use this.marked.use() to register additional markdown features (e.g., footnotes or emojis).

    Custom Async Loaders

    Pass an object to super.load() to override how libraries like marked or hljs are loaded. This allows you to use local files or different CDNs.

    // Example: Overriding the load function to set a global theme and custom template
    import ZeroMd, { STYLES } from 'https://cdn.jsdelivr.net/npm/zero-md@3'
    
    customElements.define('zero-md', class extends ZeroMd {
      async load() {
        await super.load()
        this.template = STYLES.preset('dark')
      }
    })
  9. Use Prism `line-numbers` plugin with zero-md

    main

    To use Prism's line-numbers plugin, load the Prism core, autoloader, and the line-numbers plugin via script tags. Use the manual-render attribute on <zero-md> and append the required plugin CSS using a <template data-merge="append">. Once the zero-md-ready event is received, call app.render({ classes: 'line-numbers' }) to apply the class to the markdown body.

    <head>
      <!-- Load Prism core and language autoloader -->
      <script
        defer
        data-manual
        src="https://cdn.jsdelivr.net/gh/PrismJS/prism@1/components/prism-core.min.js"
      ></script>
      <script
        defer
        src="https://cdn.jsdelivr.net/gh/PrismJS/prism@1/plugins/autoloader/prism-autoloader.min.js"
      ></script>
      <!-- Load `line-numbers` plugin -->
      <script
        defer
        src="https://cdn.jsdelivr.net/gh/PrismJS/prism@1/plugins/line-numbers/prism-line-numbers.min.js"
      ></script>
      <!-- Finally, load `<zero-md>` -->
      <script
        type="module"
        src="https://cdn.jsdelivr.net/gh/zerodevx/zero-md@2/dist/zero-md.min.js"
      ></script>
    </head>
    <body>
      <zero-md id="app" src="example.md" manual-render>
        <!-- Append CSS required for line-numbers -->
        <template data-merge="append">
          <link
            rel="stylesheet"
            href="https://cdn.jsdelivr.net/gh/PrismJS/prism@1/plugins/line-numbers/prism-line-numbers.css"
          />
        </template>
      </zero-md>
      <script>
        const app = document.querySelector('#app')
        // Listen to the ready event
        app.addEventListener('zero-md-ready', () => {
          // Then add the `line-numbers` class onto markdown body
          app.render({ classes: 'line-numbers' })
        })
      </script>
    </body>
  10. Write inline markdown with `data-dedent`

    main

    To include markdown directly in your HTML, wrap it in a <script type="text/markdown"> tag inside the <zero-md> element. This acts as a fallback if the src attribute is unset or falsy.

    To prevent leading indentation (which often causes markdown to be incorrectly interpreted as code blocks), add the data-dedent attribute to the <script> tag.

    Example:

    <zero-md>
      <script type="text/markdown" data-dedent>
        # This title won't be treated as code
        Indentation is handled.
      </script>
    </zero-md>
    <zero-md>
      <script type="text/markdown" data-dedent>
        # Opt in to apply dedent function
    
        If **indentation** is important to you.
      </script>
    </zero-md>
  11. Basic Usage: Loading and Writing Markdown

    main

    You can use <zero-md> to display markdown in three primary ways:

    1. External files: Use the src attribute to point to a URL.
    2. Inline markdown: Place markdown content inside a <script type="text/markdown"> tag within the <zero-md> element.
    3. Custom styling: Use a <template data-append> inside the element to add custom CSS that will be appended to the Shadow DOM, allowing you to override default styles while keeping the core functionality.
    <!-- Display an external markdown file -->
    <zero-md src="https://example.com/markdown.md"></zero-md>
    
    <!-- Write markdown inline -->
    <zero-md>
      <script type="text/markdown">
    # This is my [markdown](https://example.com)
      </script>
    </zero-md>
    
    <!-- Add custom styles while keeping defaults -->
    <zero-md src="https://example.com/markdown.md">
      <template data-append>
        <style>
          p { color: red; }
        </style>
      </template>
    </zero-md>