Warning
By default, <zero-md>
does not sanitise the output HTML. If you're processing markdown from
unknown or untrusted sources, please use a HTML sanitisation library
as shown below.
The following attributes apply to <zero-md>
element.
Attribute | Type | Description |
---|---|---|
src | String | URL to external markdown file. |
no-auto | Boolean | If set, disables auto-rendering. Call the render() function on that instance manually. |
no-shadow | Boolean | If set, renders and stamps into light DOM instead. Please know what you are doing. |
body-class | String | Class names forwarded to .markdown-body block. |
Notes:
-
Standard CORS rules apply; the
src
file (if fetched from another origin) should be served with the correspondingAccess-Control-Allow-Origin
headers. -
no-shadow
is immutable; it must be declared on element creation time and should not be dynamically changed.
The following attributes apply to <template>
tags.
Attribute | Type | Description |
---|---|---|
data-append | Boolean | Apply template after default template. |
data-prepend | Boolean | Apply template before default template. |
If left unset, <template>
overrides the default template.
The following convenience events are dispatched.
Event Name | Detail | Description |
---|---|---|
zero-md-ready |
undefined |
Instance setup complete and ready to render. |
zero-md-rendered |
{styles: boolean, body: boolean} |
Render completes; returns what was stamped into DOM. |
By default, render()
is automatically called once when the component is ready, and whenever a
mutation is detected. To control when rendering happens, set no-auto
on this instance.
<zero-md src="example.md" no-auto></zero-md>
<script>
// Render once when component is ready, but not when mutated
addEventListener('zero-md-ready', (e) => e.target.render())
</script>
The function returns a promise that resolves to {styles: boolean, body: boolean}
detailing which
block was stamped into DOM.
Extending functionality should be done the spec-compliant way (i.e. by extending the ZeroMd
class)
in line with the spirit of the Custom Elements V1 spec.
This runs once per element creation, just like the constructor()
, so this will be a good place
to set default values.
Change the default template globally like so:
<script type="module">
import ZeroMd from 'https://cdn.jsdelivr.net/npm/zero-md@3'
customElements.define('zero-md', class extends ZeroMd {
async load() {
await super.load()
this.template = `
<style>:host { display: block; }</style>
<link rel="stylesheet" href="path/to/markdown-styles.css" />
<link rel="stylesheet" href="path/to/highlight-styles.css" />`
}
})
</script>
Or force light
(or dark
) theme:
<script type="module">
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('light') // or STYLES.preset('dark')
}
})
</script>
Or set default attributes:
<script type="module">
import ZeroMd from 'https://cdn.jsdelivr.net/npm/zero-md@3'
customElements.define('zero-md', class extends ZeroMd {
async load() {
await super.load()
this.setAttribute('no-auto', '') // disable auto-render for all instances
this.setAttribute('no-shadow', '') // don't use shadow dom
}
})
</script>
Layer additional marked extensions you may need like so:
<script type="module">
// Add GFM Footnote functionality
// https://github.com/bent10/marked-extensions/tree/main/packages/footnote
import markedFootnote from 'https://cdn.jsdelivr.net/npm/marked-footnote@1/+esm'
import ZeroMd from 'https://cdn.jsdelivr.net/npm/zero-md@3'
customElements.define('zero-md', class extends ZeroMd {
async load() {
await super.load()
this.marked.use(markedFootnote())
}
})
</script>
Dependency libraries can be passed into the load()
function through async loaders looking like:
const lib = () => import('/path/to/lib')
This may be useful if you like to change CDN hosts, or for web projects that require libraries to be self-hosted (or bundled together).
import ZeroMd from 'zero-md'
import { Marked } from 'marked'
customElements.define('zero-md', class extends ZeroMd {
async load() {
await super.load({
marked: () => new Marked(), // self-hosted
hljs: () => import('path/to/lib'), // change CDN url
...
})
}
})
The full list of options is referenced in the katex
website. To apply, set options globally:
<script type="module">
import ZeroMd from 'https://cdn.jsdelivr.net/npm/zero-md@3'
customElements.define('zero-md', class extends ZeroMd {
async load() {
await super.load({
katexOptions: {
macros: {
N: '{\\mathbb{N}}',
Z: '\\mathbb{Z}',
Q: '\\mathbb{Q}',
R: '\\mathbb{R}'
}
}
})
}
})
</script>
This is called during every render to parse markdown into its HTML string representation, so this will be a good place to run any pre or post processing task.
If you are processing potentially unsafe markdown, always use a client-side sanitisation library.
<head>
<script defer src="https://cdn.jsdelivr.net/npm/dompurify@3/dist/purify.min.js"></script>
<script type="module">
import ZeroMd from 'https://cdn.jsdelivr.net/npm/zero-md@3'
customElements.define('zero-md', class extends ZeroMd {
async parse(obj) {
const parsed = await super.parse(obj)
return window.DOMPurify.sanitize(parsed)
}
})
</script>
</head>
<body>
<zero-md src="https://danger.com/unsafe.md"></zero-md>
</body>