Ignite Element
Framework-agnostic custom elements with typed state and events.
Ignite Element gives you a thin, typed layer around your favorite state library so you can ship web components without bringing a framework runtime.
Quick install
Section titled “Quick install”pnpm add ignite-element xstate# or npm/yarn equivalentsAdd JSX runtime settings for Ignite JSX (the default renderer):
{ "compilerOptions": { "jsx": "react-jsx", "jsxImportSource": "ignite-element/jsx" }}Create a simple machine-backed component
Section titled “Create a simple machine-backed component”import { igniteCore } from 'ignite-element/xstate';import machine from './counter-machine';
const component = igniteCore({ source: machine,});
component('my-counter', ({ state, send }) => { const { count } = state; const increment = () => send({ type: 'INCREMENT' }); const decrement = () => send({ type: 'DECREMENT' });
return ( <div class="counter"> <span class="counter-value">{count}</span> <div class="counter-buttons"> <button onClick={increment}>+</button> <button onClick={decrement}>-</button> </div> </div> );});counter-machine.ts:
import { assign, setup } from 'xstate';
const machine = setup({ types: { context: {} as { count: number }, events: {} as { type: 'INCREMENT' } | { type: 'DECREMENT' }, },}).createMachine({ id: 'counter-machine', context: { count: 0 }, initial: 'active', states: { active: { on: { INCREMENT: { actions: assign({ count: ({ context }) => context.count + 1, }), }, DECREMENT: { actions: assign({ count: ({ context }) => context.count - 1, }), }, }, }, },});
export default machine;Add the element anywhere:
<my-counter></my-counter>Want to go deeper with XState itself? See the XState docs ↗.
Try it live
Section titled “Try it live”Spin up the counter example in your browser:
- Open in StackBlitz (inline playground)
- Open repo example
Why teams pick Ignite Element
Section titled “Why teams pick Ignite Element”- Works with XState, Redux Toolkit, or MobX—bring your adapter, keep your patterns.
- Typed commands, states, and events without a React/Solid runtime; you only install the state library and renderer you pick.
- Renderer choice: Ignite JSX (default, backed by
lit-html); choose per project via config. - Built-in lifecycle handling for shared vs. isolated adapters.
- Ship design-safe components: global styles via
ignite.config.ts, per-component CSS as needed.
Ignite vs. other options
Section titled “Ignite vs. other options”- Lit / Stencil: Ignite is renderer-agnostic with pluggable adapters; keep your state library instead of adopting a bespoke reactive model.
- Framework wrappers: No React/Solid runtime required—ship native custom elements with typed events and commands.
- State-library lock-in: Swap XState/Redux/MobX without rewriting renderers; shared lifecycle handling stays consistent.
Performance snapshot
Section titled “Performance snapshot”- Tiny runtime surface—Ignite JSX uses a minimal custom JSX renderer (no framework runtime).
- Works with tree shaking; keep only the adapters/renderers you use.
- Bundle size check: Bundlephobia for the current npm release.
- Shared adapters are reference-counted to avoid duplicate subscriptions.
Choose your path
Section titled “Choose your path”- New to Ignite Element? Start with Installation then Your first component.
- Need concepts fast? Jump to State adapters and Renderers.
- Upgrading? Read v1 → v2 migration.