Vertz supports rendering raw HTML via theDocumentation Index
Fetch the complete documentation index at: https://docs.vertz.dev/llms.txt
Use this file to discover all available pages before exploring further.
innerHTML prop on any HTML host element.
This is the equivalent of React’s dangerouslySetInnerHTML — except the API is a
single plain prop, and the compiler blocks the React spelling with a clear error.
When to use it
UseinnerHTML only when you already have pre-serialized HTML that you need to
render as-is. Common cases:
- Syntax-highlighted code blocks from a highlighter (Shiki, Prism, highlight.js)
- Markdown-rendered content produced by a trusted pipeline at build time
- Sanitized rich-text (e.g. blog post bodies) that passed through a sanitizer
- Inline SVG icons wrapped in a
<span>
Basic usage
innerHTML accepts a string, null, or undefined. Nullish values render as
empty content (element.innerHTML = '').
It is reactive: when the bound signal changes, the element’s contents update.
What you cannot do
No dangerouslySetInnerHTML
Vertz rejects React’s spelling at compile time:
dangerouslySetInnerHTML={{ __html: x }}
to innerHTML={x}.
No children together with innerHTML
Setting both would discard one or the other. The compiler raises an error if you
do:
No innerHTML on SVG elements
SVG elements reject innerHTML at compile time (E0764) — SVG content
serialization uses outerHTML semantics and the DOM innerHTML setter on SVG
parses as HTML, not SVG. Wrap SVG markup in a <span> instead:
Void elements
Void HTML elements (<img>, <input>, <br>, <hr>, <meta>, <link>,
<area>, <base>, <col>, <embed>, <source>, <track>, <wbr>) cannot
contain children — setting innerHTML on them has no effect in the DOM and
should be avoided. The compiler does not currently reject this at compile time;
treat it as a runtime no-op.
Safely rendering user content
The string passed toinnerHTML is inserted verbatim. A <script> tag or an
onerror handler in the input will execute. If the content comes from anything
a user can influence — form submissions, URL parameters, database rows, API
responses — sanitize first.
The standard sanitizer is DOMPurify:
The trust boundary
innerHTML has no built-in sanitizer. This is deliberate: sanitization policy
is application-specific (what tags, what attributes, what URL schemes), and
shipping a default would either be too permissive or too restrictive.
Your app owns the trust boundary. The rule of thumb:
- Sanitize once at the edge (form handler, API response, database read)
- Mark the result as trusted in your app’s types
- Render without re-sanitizing via
innerHTML
trusted() helper from @vertz/ui:
trusted() is a nominal-type marker. It does not sanitize, transform, or
validate. It exists so reviewers can grep for trusted( and audit every
place that asserts markup is safe to render.
SSR and hydration
innerHTML works on both the server and the client. On SSR, the value is
written into the HTML response verbatim (no escaping, no sanitization). On
hydration, the hydrated element’s existing children are preserved — the first
reactive update runs after hydration completes so server-rendered content
isn’t re-written on initial paint.
If you produce the same markup on the server and client, there is no visible
flash or mismatch warning.
Full example: syntax-highlighted code
Migrating from React
| React | Vertz |
|---|---|
<div dangerouslySetInnerHTML={{ __html: x }} /> | <div innerHTML={x} /> |
null/undefined → empty | Same — nullish → empty |
| Sanitize with DOMPurify | Same — DOMPurify works |
| Children + dangerouslySetInnerHTML (React warns) | Compile error E0761 |
Summary
innerHTMLis a plain prop on HTML host elementsdangerouslySetInnerHTMLis a compile error — useinnerHTML- Never pass untrusted input; sanitize at the boundary with DOMPurify
- Wrap sanitized values with
trusted()for audit clarity - Mutually exclusive with children (E0761); forbidden on SVG elements (E0764)