Skip to content

9 · raw() + sanitisation

raw(html) injects pre-escaped HTML into the JSX output, no further escaping. Use it for: pre-rendered Markdown, server fragments, SVG icon literals, sanitised user input. It’s new SafeHtml(html) — the caller is responsible for ensuring the input is safe.

What to look at: marked produces HTML, DOMPurify cleans it, raw() injects the cleaned string verbatim. Try typing <script>alert(1)</script> — the script tag is stripped by DOMPurify before it ever reaches the DOM.

src/main.tsx
import { signal, mount, raw, delegate } from 'kerfjs';
import { marked } from 'marked';
import DOMPurify from 'dompurify';
const source = signal(`# Hello\n\nType **bold** and *italic*.`);
function render(md: string) {
const html = marked.parse(md, { async: false }) as string;
return DOMPurify.sanitize(html);
}
const root = document.getElementById('app')!;
mount(root, () => (
<div class="kerf-stack">
<div class="kerf-split-md">
<div>
<p class="kerf-section-label">Markdown</p>
<textarea
data-source
class="kerf-mono"
rows={12}
style="resize: vertical;"
>{source.value}</textarea>
</div>
<div>
<p class="kerf-section-label">Rendered</p>
<article class="kerf-output" style="overflow: auto;">
{raw(render(source.value))}
</article>
</div>
</div>
</div>
));
delegate(root, 'input', '[data-source]', (_, ta) => {
source.value = (ta as HTMLTextAreaElement).value;
});

Install: npm install marked dompurify. Both are optional — kerf doesn’t depend on either; this example reaches for them only because rendering Markdown safely is the canonical reason to use raw().