markdown
<tosi-md> renders markdown using marked.
<tosi-md> renders markdown anywhere, either using the
src attribute to load the file asynchronously, or rendering the text inside it.
<tosi-md sanitize="on">
## hello
world

| this | is | a | table |
|-------|------|-------|-------|
| one | two | three | four |
| five | six | seven | eight |
</tosi-md>
tosi-md {
display: block;
padding: var(--spacing);
}
Note that, by default, <tosi-md> will use its textContent (not its innerHTML) as its source.
sanitize — on by default
Markdown can contain raw HTML, and <tosi-md> renders whatever the markdown produces. For text
you did not write (issue bodies, comments, anything from a user or an API), unsanitized
rendering is a stored XSS: <img src=x onerror=…> or a javascript: link runs in your page.
So <tosi-md> sanitizes by default (since 1.16) with
kilpi: event-handler attributes, unsafe URL schemes
and links that are not safe to navigate to are stripped, and these elements are removed
together with everything inside them: script, style, iframe, object, embed, form,
link, meta, base, noscript, template, and SVG animation elements. Everything else
survives, including inputs.
Custom elements are unwrapped when sanitizing (their content is kept, the element is not),
because a component is code: some render raw HTML or run code of their own. Allow the ones you
trust by name with the allowed-elements attribute (space- or comma-separated), e.g.
<tosi-md allowed-elements="tosi-icon tosi-tag">, or the allowedElements property. An allowed
element keeps whatever attributes the markdown's author gave it, so allow only display components.
tosi-md, tosi-example and tosi-doc-system are never allowed: they render raw HTML or run code.
sanitize="off" renders the HTML as-is. Use it only for markdown you control, for example
markup that embeds a <form> (see elements below).
rendering markdown from a url
Again, like an <img> tag, you can simply set a <tosi-md>'s src attribute to a URL pointing
to markdown source and it will load it asynchronously and render it.
<tosi-md src="/path/to/file.md">
setting its value
Or, just set the element's value and it will render it for you. You can try
this in the console, e.g.
$('.preview tosi-md').value = 'testing\n\n## this is a test'
elements
<tosi-md> also (optionally) allows the embedding of inline HTML elements without blocking markdown
rendering, so that you can embed specific elements while retaining markdown. You need to explicitly set
the elements property, and for markdown rendering not to be blocked, the html elements need to
start on a new line and not be indented. E.g.
This example uses sanitize="off": it is markup the page's author wrote, and sanitize="on"
removes a <form> together with everything inside it.
<tosi-md elements sanitize="off">
<form>
### this is a form
<label>
fill in this field.
**It's important!**
<input>
</label>
</form>
</tosi-md>
test('the embedded form renders, with markdown inside it', () => {
const md = preview.querySelector('tosi-md[elements]')
expect(md.querySelector('form input')).toBeTruthy()
expect(md.querySelector('form h3').textContent).toBe('this is a form')
expect(md.querySelector('form strong').textContent).toBe("It's important!")
})
In this case <tosi-md> uses its innerHTML and not its textContent.
context and template variables
<tosi-md> also supports template values. You need to provide data to the element in the form
of context (an arbitrary object, or a JSON string), and then embed the template text using
handlebars-style doubled curly braces, e.g. {{path.to.value}}.
If no value is found, the original text is passed through.
Finally, note that template substitution occurs before markdown transformation, which means you can pass context data through to HTML elements.
<tosi-md
elements
sanitize="on"
context='{"title": "template example", "foo": {"bar": 17}, "nested": "*work*: {{foo.bar}}"}'
>
## {{title}}
The magic number is <input type="number" value={{foo.bar}}>
Oh, and nested templates {{nested}}.
</tosi-md>