Skip to content

Ignite Element

Platform-native custom elements for modern state-driven UI.

Ignite Element is a thin, typed layer around modern state systems so you can ship platform-native custom elements without dragging along an app-framework runtime. Commands express intent, effects express consequences, and the same component contract runs in the DOM, in tests, or headlessly.

import { igniteCore } from 'ignite-element/xstate';
import { toggleMachine } from './toggle-machine';
const toggle = igniteCore({
source: toggleMachine,
view: ({ matches }) => ({ isOn: matches('on') }),
commands: ({ actor }) => ({ toggle: () => actor.send({ type: 'TOGGLE' }) }),
});
toggle('ignite-toggle', ({ isOn, toggle }) => (
<button onClick={toggle}>{isOn ? 'On' : 'Off'}</button>
));

That registration is both a <ignite-toggle> custom element and a headless runtime you can drive from tests or agents — no DOM required.

New to the idea entirely? Read What is Ignite Element? for the why and how it compares to other tools.

Try the counter directly in the docs, or open the full example in StackBlitz.

<ignite-counter>

0

Every press is a command — the buttons express intent, the state machine owns the transition, and the view re-renders from state. Here is the same counter with the real API:

import { igniteCore } from 'ignite-element/xstate';
import { counterMachine } from './counter-machine';
const counter = igniteCore({
source: counterMachine,
view: ({ context }) => ({ count: context.count }),
commands: ({ actor }) => ({
increment: () => actor.send({ type: 'INC' }),
decrement: () => actor.send({ type: 'DEC' }),
reset: () => actor.send({ type: 'RESET' }),
}),
});
counter('ignite-counter', ({ count, increment, decrement, reset }) => (
<div>
<button onClick={decrement}></button>
<output>{count}</output>
<button onClick={increment}>+</button>
<button onClick={reset}>Reset</button>
</div>
));

Want to edit and fork the full project?