This example demonstrates how to use ignite-element with XState, lit-html, and TailwindCSS for styling.
- State management with XState, showcasing shared and isolated components.
- Unified API for accessing state values, with options to use
state
orstate.context
. - Styling with TailwindCSS.
- Integration with ignite-element for seamless web component creation.
Run the following command to install all necessary dependencies:
npm install
To start the development server:
npm run dev
When running the example, you'll see:
- Shared Counter Component: A counter component using a shared global state.
- Isolated Counter Component: A counter component with isolated state for each instance.
This example uses TailwindCSS for component styling. To apply global styles, use the setGlobalStyles
function to reference the compiled Tailwind CSS file:
import { setGlobalStyles } from "ignite-element";
setGlobalStyles("./dist/styles.css");
With the updated XStateAdapter
, you can access state values directly from state
or through state.context
. This provides flexibility for different use cases:
- Direct Access: Access flattened
context
values directly fromstate
(e.g.,state.count
). - Context Access: Access the original
context
object viastate.context
for compatibility with XState conventions.
@Shared("counter-component")
export class CounterComponent {
render({ state, send }: RenderArgs<typeof counterMachine>) {
const { count } = state; // Direct access to count from state
// const { count } = state.context; - Or access through context explicitly
return html`
<div class="p-4 bg-gray-100 border rounded-md">
<h3 class="text-lg font-bold">Counter Component</h3>
<p class="text-xl">Count: ${count}</p>
<div class="mt-4 space-x-2">
<button
class="px-4 py-2 bg-red-500 text-white rounded hover:bg-red-600"
@click=${() => send({ type: "DEC" })}
>
-
</button>
<button
class="px-4 py-2 bg-green-500 text-white rounded hover:bg-green-600"
@click=${() => send({ type: "INC" })}
>
+
</button>
</div>
</div>
`;
}
}
Create an XState machine for managing the component's state:
import { createMachine } from "xstate";
const counterMachine = createMachine({
id: "counter",
initial: "active",
context: { count: 0 },
states: {
active: {
on: {
INC: { actions: "increment" },
DEC: { actions: "decrement" },
},
},
},
});
Add global styles for TailwindCSS using setGlobalStyles
:
import { setGlobalStyles } from "ignite-element";
setGlobalStyles("./dist/styles.css");
Restructure igniteCore
to export shared
and isolated
methods directly:
import { igniteCore } from "ignite-element";
import counterMachine from "./counterMachine";
export const { shared, isolated } = igniteCore({
adapter: "xstate",
source: counterMachine,
});
shared("shared-counter", (state, send) => {
return html`
<div class="p-4 bg-gray-100 border rounded-md mb-2">
<h3 class="text-lg font-bold">Shared Counter (XState)</h3>
<p class="text-xl">Count: ${state.context.count}</p>
<div class="mt-4 space-x-2">
<button
class="px-4 py-2 bg-red-500 text-white rounded hover:bg-red-600"
@click=${() => send({ type: "DEC" })}
>
-
</button>
<button
class="px-4 py-2 bg-green-500 text-white rounded hover:bg-green-600"
@click=${() => send({ type: "INC" })}
>
+
</button>
</div>
</div>
`;
});
isolated("isolated-counter", (state, send) => {
return html`
<div class="p-4 bg-yellow-100 border rounded-md mb-2">
<h3 class="text-lg font-bold text-yellow-800">
Isolated Counter (XState)
</h3>
<p class="text-xl text-yellow-700">Count: ${state.context.count}</p>
<div class="mt-4 space-x-2">
<button
class="px-4 py-2 bg-purple-500 text-white rounded hover:bg-purple-600"
@click=${() => send({ type: "DEC" })}
>
-
</button>
<button
class="px-4 py-2 bg-teal-500 text-white rounded hover:bg-teal-600"
@click=${() => send({ type: "INC" })}
>
+
</button>
</div>
</div>
`;
});
Use the custom elements in your HTML file:
<shared-counter></shared-counter>
<isolated-counter></isolated-counter>