Every component. Every state. Your real CSS.
Zandbox is a component lab for Bun + HTMX projects. Every component, in every state, on its own stage — styled by the CSS your app actually ships, so what you see here is what your users get. No build step, no rendering library, no second design system to keep in sync.
Dev-only. Binds 127.0.0.1, ships nowhere near production.
Components — Button — states
button-statesThis lab built Zimer's interface: 60 stories, 13 groups, 20 tokens from its DESIGN.md — every screen checked here before it shipped.
How it works
Your components never know Zandbox exists. A story is a thin file that renders one component in a given state; a single config file gathers the stories and maps your assets. The engine — one small Bun server — does the rest.
Write a story
One .stories.ts file per component: the component, its states, fictional data. Kept apart from the component, Storybook-style.
Register it once
zandbox.config.ts gathers your story arrays, maps your stylesheet, and points at your DESIGN.md if you keep one.
Browse the lab
bun run zandbox — the terminal names any story that fails to render; then pick a story in the sidebar and see it alone on the stage. Filter as you type; every story has a shareable URL.
Built for how Bun + HTMX projects actually work
Four things a lab owes you when your components are server functions, not framework components.
Catch a broken state before your users do
At startup the lab renders every story once and names the ones that throw — in your terminal, before you open the browser. The state you would have found by clicking is the state it reports.
What you see is what ships
The lab serves your stylesheet as-is, and your components return the same HTML here that they return in the app. There is no preview layer to drift from production.
Your spec, rendered
Point designMd at your DESIGN.md and every color token becomes a swatch story. When the spec and the screen disagree, you can see it — and so can anyone reviewing the change.
Any component, seconds away
Filter the sidebar as you type, open a story's bare canvas, share its URL with a reviewer. Stories are files in git next to the components — not rows in a database, not a second codebase.
The terminal tells you the truth at startup
A real Zandbox boot, on loop. This is the whole startup output — nothing is summarized away.
Why not Storybook?
A fair question — it is the default. The answer is shape.
Storybook's shape
Framework components rendered through a bundler build: JSX or a framework renderer, a config of addons, a second build to keep green. Superb — if your project already has that machinery.
Zandbox's shape
One Bun server and one config file. Your components already return HTML strings; your CSS already exists. There is nothing to compile and nothing new to adopt.
Honestly: if you ship React or Vue with a bundler in the project, Storybook is the right tool and this page is not for you. If your components are functions that return HTML, there is nothing for Storybook to render — and Zandbox starts exactly there.
Questions, answered
Does it work with React or Vue components?
No. Zandbox renders components that return HTML strings — server templates and Web Components. Framework components belong in Storybook.
Can any of this reach production?
No. The engine lives in a hidden .zandbox/ folder, binds 127.0.0.1 only, and renders fictional data. It is a development tool by construction, not by configuration.
How do I update the engine?
Delete .zandbox/ and re-run init. Your config, your stories, and your components are never touched — they were never the engine's.
What does it cost?
Nothing. MIT licensed, source on GitHub, built on Bun.
Get started
Clone Zandbox once, run init inside your project, start the lab. About five minutes, most of it the clone.