The k-markdown component takes its child text content (or a value attribute), parses it as markdown using marked (full CommonMark + GFM — tables, task lists, fenced code, autolinks, inline HTML), runs the result through sanitizeHtml, and renders the HTML in place. It renders to the light DOM so page-level typography styles cascade naturally into headings, paragraphs, tables, and so on.
Common leading whitespace is automatically stripped from the source so you can indent the markdown to match the surrounding HTML without breaking parsing.
Drop markdown text inside the tag and it will be replaced with the rendered HTML when the element connects.
<k-markdown>
# Hello World
This is **bold** and *italic* text.
- list item 1
- list item 2
</k-markdown>
Skip the children and pass markdown directly via the value attribute when you only need a single line. The attribute also takes precedence over child content if both are provided.
<k-markdown value="Visit [Kempo UI](https://github.com/dustinpoissant/kempo-ui) for more."></k-markdown>
By default, single newlines are joined into a paragraph (CommonMark behavior). Add the breaks attribute to convert single newlines to <br> — the Slack/iMessage convention — useful for chat-style content.
<k-markdown breaks>
Line one
Line two
Line three
</k-markdown>
The rendered HTML is sanitized with the same allowed-tags / disallowed-tags controls used by k-markdown-editor. Pass a comma-separated allowlist (or * for everything), or a comma-separated denylist — the two are mutually exclusive. <script>, <iframe>, <style>, and similar tags are always stripped unless you opt in with scripts-enabled (which only restores <script>).
<k-markdown allowed-tags="p,strong,em,a">
Only **bold**, *italic*, [links](https://example.com), and paragraphs are kept.
# This heading will be unwrapped
</k-markdown>
Set the value property in JavaScript to re-render with new markdown.
<k-markdown id="dynamicMd" value="Click the button."></k-markdown>
<button id="dynamicMdBtn">Update</button>
<script type="module">
const md = document.getElementById('dynamicMd');
const btn = document.getElementById('dynamicMdBtn');
let toggled = false;
btn.addEventListener('click', () => {
toggled = !toggled;
md.value = toggled
? '## Updated!\n\nThis was set via JavaScript with **markdown** and a [link](https://example.com).'
: 'Click the button.';
});
</script>
marked (vendored at src/utils/marked.esm.js) via renderMarkdownsanitizeHtmlvalue: stringThe markdown source. If empty when the element connects, the component falls back to the dedented child text content. Setting this property at runtime re-renders the output.
breaks: booleanWhen true, single newlines convert to <br> instead of being joined into a paragraph. Defaults to false. Reflects to the breaks attribute.
allowedTags: stringComma-separated allowlist for the rendered HTML. Pass * to allow every tag. Mutually exclusive with disallowedTags — if both are set, allowedTags wins and a console warning is logged. Reflects to the allowed-tags attribute.
disallowedTags: stringComma-separated denylist — everything is allowed except the listed tags. Reflects to the disallowed-tags attribute.
scriptsEnabled: booleanWhen present, <script> tags survive sanitization (provided they also pass the allow/deny tag check). Defaults to off so script content can never reach the DOM. Reflects to the scripts-enabled attribute.
renderedHtml: string (getter)Returns the sanitized HTML string that was rendered — useful for copying the output or feeding it into another component.