hp-latex
LaTeX math primitive. Render-only Lit element with a consumer-registered engine —
hp-latex ships no math engine. A consumer that wants math installs the engine of
their choice (KaTeX,
MathJax,
Temml, …) and registers an adapter
once at startup via HpLatex.setRenderer(...). Source comes from the
value attribute or the element's text content (attribute wins).
Without a registered renderer, the source renders as mono-spaced text — same
fallback shape as <hp-code>
with no tokeniser.
throwOnError: false
— every <hp-latex> on the page renders via KaTeX, and broken
LaTeX emits an inline red .katex-error span instead of throwing.
hp-latex is the only light-DOM hp-* element in the system — see
the Intent tab for the rationale.
Einstein's mass-energy equivalence is
The roots of
Good:
Bad:
Install
bun add @hexpunk/core lit import "@hexpunk/core"; Properties
| Property | Attribute | Type | Default | Description |
|---|---|---|---|---|
value | value | string | "" | LaTeX source string |
block | block | boolean | false | Switch to block (display) mode (default: inline) |
background | background | boolean | false | Mount an hp-background backdrop (block-mode only) |
copyable | copyable | boolean | false | Show a copy-source button in the top-right corner (block-mode only) |
Events
| Event | Type | Description |
|---|---|---|
render-error | CustomEvent | Bubbling CustomEvent when the renderer throws; detail = { error, latex } |
Setting up the renderer
hp-latex ships no engine to keep @hexpunk/core dependency-free.
Install KaTeX (or another engine), register it once at startup. Every connected
<hp-latex> re-renders automatically when a new renderer is set.
throwOnError: false tells KaTeX to render an inline red error span
instead of throwing on malformed input — the rest of the page keeps rendering.
The try/catch returns null on any unexpected failure, which
triggers hp-latex's mono-spaced source fallback. Failures also dispatch a
bubbling render-error CustomEvent
(detail: { error, latex }) so consumers can log them.
Why light DOM?
hp-latex is the only light-DOM hp-* element in the system —
createRenderRoot() returns this. KaTeX outputs HTML
scoped by .katex / .katex-mathml /
.katex-html classes and depends on ~2000 lines of CSS plus
@font-face rules to render correctly; shadow-DOM encapsulation
would block that cascade. Light DOM lets the consumer's global
katex.min.css reach the math naturally. The deviation from the
hp-* convention is intentional and documented in the element's source.
Alternatives
The renderer slot is engine-agnostic — anything that returns an HTML string works:
- KaTeX (0.17.0, May 2026). Fast, synchronous, comprehensive LaTeX subset. ~70 KB JS + ~25 KB CSS + font files. Default pick.
- Temml (0.13.3, May 2026). Pure LaTeX → MathML converter. ~30 KB, no fonts (relies on browser MathML). Smaller payload; rendering fidelity varies by browser.
- MathJax v4 (4.1.2, May 2026). Broader LaTeX coverage, accessibility extensions, async renderer. ~400 KB+. Reach for it when KaTeX's subset isn't enough.
For build-time pre-rendered math in static MDX docs (independent of hp-latex),
use Astro's remark-math
+ rehype-katex plugins. That path produces zero-runtime-JS math
directly in HTML and is the right call for static docs. hp-latex is for
dynamic / interactive / programmatically-driven math.
When to use
value attribute when the source contains characters HTML
doesn't love (<, >, & inside
inequalities). The slot fallback is fine for static prose where the source is
plain.
block with background for a one-off "system-styled"
featured equation — drops an <hp-background> behind the math
without needing a wrapper.
copyable when readers might want to grab the LaTeX source —
docs pages walking through derivations, reference cards, anywhere the
expression itself is the takeaway. The button writes the
value attribute to the clipboard via the async Clipboard API.
<hp-code> when you want it rendered. hp-code
treats its content as plain code (or syntax-highlighted), not math. Reach for
hp-latex when the intent is "show the math".
output: "static" if you
need pre-rendered math at build time — light DOM is incompatible with
@lit-labs/ssr. Use remark-math + rehype-katex
in your Astro/MDX config instead.
Accessibility
KaTeX emits MathML alongside its rendered HTML so screen readers can announce
the math semantically (<math> inside the
.katex-mathml span). The visual .katex-html span is
aria-hidden. No extra setup needed.
For the no-renderer fallback, the source renders as a plain
<span class="hp-latex-source"> — screen readers read the
LaTeX source as text. Consumers wanting better fallback semantics can listen
for render-error and surface a user-facing message.
- 0.1.0-beta 2026-05-24
Added
<hp-latex>— render-only LaTeX math primitive. Consumer-registered renderer viaHpLatex.setRenderer((latex, "inline" | "block") => string | null);@hexpunk/corehas zero math-engine dependency.valueattribute carries the LaTeX source (text content fallback captured once on connect). Boolean attributes:block(block/display mode, centred + full-width),background(mounts<hp-background>backdrop inside the element, block mode only),copyable(mounts<hp-copy>source button in the top-right corner, block mode only). Without a renderer, source renders mono-spaced fallback;render-errorCustomEvent dispatches on renderer throw. Only light-DOM hp-\* element in the system — required for KaTeX's class-scoped CSS to cascade into the rendered output (file header explains the rationale). Not SSR-friendly via@lit-labs/ssr; consumers wanting pre-rendered math in MDX use Astro'sremark-math+rehype-katexdirectly.<hp-copy>— copy-to-clipboard button widget. Lucidecopyicon + slotted label (translatable per-instance, default "Copy") + sibling "Copied" toast witharia-live="polite".valueattribute for the text to copy;copiedattribute for the toast text;icon-onlyboolean drops the visible label while keeping it in the a11y tree. Bubblinghp-copy-success/hp-copy-errorevents. Async Clipboard API only — noexecCommandfallback. Now powers<hp-demo>'s copy-code action and<hp-latex>'s source-copy button.@hexpunk/core/hp-latex.css— light-DOM chrome stylesheet for<hp-latex>(display modes, backdrop positioning, source-fallback typography). Consumer imports alongsideelements.cssandkatex.min.css.
Changed
<hp-demo>copy action — replaced the bespoke inline copy button + animated toast with<hp-copy>so the same widget powers both<hp-demo>and<hp-latex>. Slot-text source caching viaslotchangeon the code slot; no behaviour change for consumers.