Skip to content

Your first component

This guide assumes you completed Installation. We’ll build a toggle button with XState and the Ignite JSX renderer.

import { createMachine } from 'xstate';
export const toggleMachine = createMachine({
id: 'toggle',
initial: 'off',
states: {
off: { on: { TOGGLE: 'on' } },
on: { on: { TOGGLE: 'off' } },
},
});
import { igniteCore } from 'ignite-element/xstate';
import { toggleMachine } from './toggleMachine';
const registerToggle = igniteCore({
source: toggleMachine,
events: (event) => ({ toggled: event<{ isOn: boolean }>() }),
view: ({ matches }) => ({ isOn: matches('on') }),
commands: ({ actor }) => ({
toggle: () => {
actor.send({ type: 'TOGGLE' });
},
}),
effects: ({ emit, select }) => {
const isOn = select((snapshot) => snapshot.matches('on'));
if (!isOn.changed) return;
emit('toggled', { isOn: isOn.current });
},
});
registerToggle('ignite-toggle', ({ isOn, toggle }) => (
<>
<style>{`
.ignite-toggle {
border-radius: 12px;
padding: 0.75rem 1.25rem;
border: 1px solid #1ad2ff;
background: radial-gradient(circle at 20% 20%, rgba(26, 210, 255, 0.15), transparent 50%),
#0f182e;
color: #e2e8f0;
}
`}</style>
<button class="ignite-toggle" onClick={toggle}>
{isOn ? 'On' : 'Off'}
</button>
</>
));

Because it’s a web component, drop the tag into plain HTML or any host framework:

<ignite-toggle></ignite-toggle>

In Ignite JSX, the toggled event you declared becomes an onToggled prop; read the payload via event.detail. For concrete React, Vue, plain-HTML, and SSR patterns, see Host app integration.

  • Swap source for a Redux slice or MobX store via ignite-element/redux or ignite-element/mobx.
  • Keep styles local by default; reach for shared style injection only in the advanced @ignite-element/renderer path.
  • Opt into the legacy lit renderer only if you need it, via the advanced docs path.
  • Share actors/stores by passing long-lived instances. Ignite never stops user-owned sources.
  • Advanced overrides: a consumer-owned shared adapter stays alive for the core’s lifetime by default; set cleanup: true only to opt into element-refcount teardown.

You shipped a working component — here’s where to go from here: