Skip to content

Rendering

A view returns one of two things: an Ignite JSX element (the default) or a lit-html template. Ignite renders each with the matching strategy, and it picks the strategy automatically from what the view returns — no ignite.config.ts, no plugin, and no renderer setting.

Both styles use the same view/commands contract; they differ only in how you write the markup.

JSX syntax, rendered by Ignite’s built-in diffing renderer. It ships with the package and registers itself:

const Counter = component('ignite-counter', ({ count }) => (
<output>Count: {count}</output>
));

JSX is compiled<output> becomes a jsx(...) call at build time — so you must point the JSX transform at ignite-element/jsx (see Where jsxImportSource lives).

A html tagged template, rendered by the lit strategy. Unlike JSX, a tagged template is plain runtime JavaScript — nothing to compile. Install lit-html and import the strategy once to register it:

import '@ignite-element/renderer/lit';
import { html } from 'lit-html';
const Counter = component('ignite-counter', ({ count }) =>
html`<output>Count: ${count}</output>`
);

Ignite JSX needs the compiler told to use its JSX runtime. That is the jsxImportSource setting, and it can live in any one of three places — pick whichever fits your project:

WhereUse it when
Global tsconfig.json"jsxImportSource": "ignite-element/jsx"Every JSX file is Ignite JSX. The common case; see Installation.
Per-file pragma — /** @jsxImportSource ignite-element/jsx */You mix runtimes in one project (e.g. React app files alongside Ignite element files).
Bundler config — esbuild/Vite jsxImportSourceYou drive JSX through the bundler instead of tsconfig (e.g. a plain-JavaScript build).

lit-html needs none of this — a html template is not compiled.

On the config-free path, Ignite resolves the strategy from each view’s output:

  • a lit-html TemplateResult (with @ignite-element/renderer/lit imported) → the lit strategy;
  • anything else → Ignite JSX.

A lit view rendered without importing the lit strategy falls back to Ignite JSX unchanged (no error) — importing the strategy is what upgrades it. To force one renderer project-wide regardless of output, set renderer in ignite.config.ts; that explicit override wins over auto-detection.

Nothing here requires TypeScript — TS only adds type-checking on top. What a renderer needs depends on whether its markup is compiled:

AuthoringNo build step (raw .js in the browser)With a bundler (.js/.jsx, no TS)
lit-html (html template)✅ runtime tagged template
Ignite JSX (<div/> syntax)❌ JSX must be transformed✅ set jsxImportSource in the bundler
Ignite JSX (jsx(...) calls)✅ plain function calls

<div/> is not valid JavaScript, so it cannot run untransformed. With no build step you can still use Ignite JSX by calling its runtime directly — jsx/jsxs/Fragment are exported from ignite-element/jsx/jsx-runtime, the same functions JSX compiles to:

import { jsx } from 'ignite-element/jsx/jsx-runtime';
const view = ({ count }) => jsx('output', { children: `Count: ${count}` });

For a no-build setup, lit-html is usually the simpler choice: it needs only an import map for the bare ignite-element specifiers — the standard way to run ESM in the browser.

  • Installation — the jsxImportSource tsconfig setup.
  • Advanced config — the project-wide renderer override, shared styles, and render-strategy primitives.
  • Styling — component CSS inside the shadow root.