A page lifts off the components it's built from, which lift off the tokens under them. Numbered labels, with the active layer's description under the stack.
@keyframeui
registry/demos/exploded-ui-design-system-demo.tsx
"use client";
import * as React from "react";
import { cn } from "@/lib/utils";
import { ExplodedUI } from "@/components/ui/exploded-ui";
// Sized off the plane's width, so each layer scales like an image.
const screen =
"[--spacing:0.4cqw] [--text-xs:1.2cqw] [--text-sm:1.4cqw] [--text-base:1.6cqw] [--text-lg:1.9cqw] [--text-2xl:2.6cqw] [--text-4xl:4cqw] [--radius-md:0.6cqw] [--radius-lg:0.8cqw] [--radius-xl:1.2cqw]";
// The page on top is built from the components under it, which are built from
// the tokens at the bottom: the same three colors run through all of them.
export function ExplodedUIDesignSystemDemo() {
const scrollRef = React.useRef<HTMLDivElement>(null);
return (
<div className="relative w-full overflow-hidden rounded-xl border border-zinc-200 bg-stone-100 text-zinc-950 dark:border-zinc-800 dark:bg-zinc-950 dark:text-zinc-50">
<div ref={scrollRef} className="relative h-[var(--demo-height,36rem)] overflow-y-auto overscroll-contain">
<header className="mx-auto max-w-2xl px-6 pt-16 pb-4 text-center sm:pt-20">
<p className="text-sm font-medium text-orange-600 dark:text-orange-400">Fieldwork Design System</p>
<h2 className="mt-3 text-3xl font-semibold tracking-tight text-balance sm:text-4xl">
Every page starts as three decisions
</h2>
</header>
<ExplodedUI
walkthrough
labels="numbered"
spread={0.16}
containerRef={scrollRef}
stageClassName="h-[var(--demo-height,36rem)]"
className={cn("aspect-[16/10] w-full max-w-2xl", screen)}
>
<ExplodedUI.Layer label="Tokens" description="Color, type and spacing, decided once.">
<Tokens />
</ExplodedUI.Layer>
<ExplodedUI.Layer
label="Components"
description="Buttons, fields and toggles built from the tokens."
className="inset-[7%]"
>
<Components />
</ExplodedUI.Layer>
<ExplodedUI.Layer label="Pages" description="Composed from components. Nothing one-off.">
<Page />
</ExplodedUI.Layer>
</ExplodedUI>
<section className="mx-auto max-w-xl px-6 py-16 text-center text-zinc-600 dark:text-zinc-400">
120 components, 2 themes, 0 hex codes in product code.
</section>
</div>
</div>
);
}
const palette = [
["Ink", ["bg-zinc-50", "bg-zinc-200", "bg-zinc-400", "bg-zinc-700", "bg-zinc-950"]],
["Clay", ["bg-orange-50", "bg-orange-200", "bg-orange-400", "bg-orange-600", "bg-orange-800"]],
["Moss", ["bg-lime-50", "bg-lime-200", "bg-lime-400", "bg-lime-600", "bg-lime-800"]],
] as const;
function Tokens() {
return (
<div className="grid size-full grid-cols-[1.3fr_1fr] gap-6 bg-white p-6 text-xs text-zinc-500 dark:bg-zinc-900 dark:text-zinc-400">
<div className="flex flex-col gap-4">
<span className="font-mono">color</span>
{palette.map(([name, swatches]) => (
<div key={name} className="flex items-center gap-3">
<span className="w-10">{name}</span>
<div className="flex flex-1 gap-1.5">
{swatches.map((swatch) => (
<span key={swatch} className={cn("aspect-square flex-1 rounded-md ring-1 ring-zinc-950/5", swatch)} />
))}
</div>
</div>
))}
</div>
<div className="flex flex-col gap-3">
<span className="font-mono">type</span>
<span className="text-4xl leading-none font-semibold tracking-tight text-zinc-950 dark:text-zinc-50">Aa</span>
{[
["display", "40 / 44"],
["title", "24 / 30"],
["body", "16 / 24"],
].map(([name, size]) => (
<span key={name} className="flex justify-between border-b border-zinc-950/5 pb-1.5 dark:border-white/10">
{name}
<span className="font-mono">{size}</span>
</span>
))}
<span className="mt-2 font-mono">space</span>
<div className="flex items-end gap-1.5">
{[1, 2, 3, 4, 6, 8].map((n) => (
<span key={n} className="rounded-sm bg-orange-400/70" style={{ width: `${n * 0.5}cqw`, height: `${n * 0.5}cqw` }} />
))}
</div>
</div>
</div>
);
}
function Components() {
return (
<div className="grid size-full grid-cols-2 content-center gap-x-8 gap-y-6 bg-stone-50 p-8 text-xs dark:bg-zinc-800">
<div className="flex flex-wrap items-center gap-2">
<span className="rounded-lg bg-zinc-950 px-4 py-2 font-medium text-white dark:bg-white dark:text-zinc-950">Primary</span>
<span className="rounded-lg px-4 py-2 font-medium ring-1 ring-zinc-950/15 ring-inset dark:ring-white/20">Secondary</span>
<span className="rounded-lg bg-orange-600 px-4 py-2 font-medium text-white">Accent</span>
</div>
<div className="flex items-center gap-3">
<span className="flex h-6 w-11 items-center rounded-full bg-lime-600 p-0.5">
<span className="ml-auto size-5 rounded-full bg-white shadow-sm" />
</span>
<span className="flex size-5 items-center justify-center rounded-md bg-zinc-950 text-white dark:bg-white dark:text-zinc-950">
<svg viewBox="0 0 12 12" aria-hidden className="size-3 fill-none stroke-current" strokeWidth="2">
<path d="m2.5 6.5 2.5 2.5 4.5-6" />
</svg>
</span>
<span className="rounded-full bg-lime-100 px-2.5 py-1 font-medium text-lime-800 dark:bg-lime-900/50 dark:text-lime-200">Shipped</span>
</div>
<div className="flex flex-col gap-1.5">
<span className="font-medium">Email</span>
<span className="rounded-lg bg-white px-3 py-2 text-zinc-400 ring-1 ring-zinc-950/10 dark:bg-zinc-900 dark:ring-white/10">you@fieldwork.co</span>
</div>
<div className="flex -space-x-2">
{["bg-orange-300", "bg-lime-300", "bg-zinc-300", "bg-orange-500"].map((color) => (
<span key={color} className={cn("size-8 rounded-full ring-2 ring-stone-50 dark:ring-zinc-800", color)} />
))}
</div>
</div>
);
}
function Page() {
return (
<div className="flex size-full flex-col bg-orange-50 p-6 text-xs dark:bg-zinc-900">
<div className="flex items-center justify-between">
<span className="flex items-center gap-2 text-sm font-semibold">
<span className="size-5 rounded-full bg-orange-600" />
Fieldwork
</span>
<div className="flex items-center gap-5 text-zinc-600 dark:text-zinc-400">
<span>Product</span>
<span>Pricing</span>
<span className="rounded-lg bg-zinc-950 px-3 py-1.5 font-medium text-white dark:bg-white dark:text-zinc-950">Sign up</span>
</div>
</div>
<div className="mt-[8%] grid flex-1 grid-cols-[1.2fr_1fr] gap-6">
<div>
<span className="rounded-full bg-lime-100 px-2.5 py-1 font-medium text-lime-800 dark:bg-lime-900/50 dark:text-lime-200">Shipped: v4</span>
<p className="mt-4 text-4xl leading-[1.05] font-semibold tracking-tight text-balance">Field notes for teams that build</p>
<div className="mt-6 flex gap-2">
<span className="rounded-lg bg-orange-600 px-4 py-2 font-medium text-white">Start free</span>
<span className="rounded-lg px-4 py-2 font-medium ring-1 ring-zinc-950/15 ring-inset dark:ring-white/20">Book a demo</span>
</div>
</div>
<div className="flex flex-col gap-3 self-start rounded-xl bg-white p-5 shadow-xl ring-1 shadow-orange-950/10 ring-zinc-950/5 dark:bg-zinc-800 dark:ring-white/10">
<span className="font-medium">Join the beta</span>
<span className="rounded-lg bg-white px-3 py-2 text-zinc-400 ring-1 ring-zinc-950/10 dark:bg-zinc-900 dark:ring-white/10">you@fieldwork.co</span>
<span className="flex items-center gap-2 text-zinc-500">
<span className="flex h-5 w-9 items-center rounded-full bg-lime-600 p-0.5">
<span className="ml-auto size-4 rounded-full bg-white" />
</span>
Weekly digest
</span>
<span className="mt-2 rounded-lg bg-zinc-950 py-2 text-center font-medium text-white dark:bg-white dark:text-zinc-950">Request access</span>
</div>
</div>
</div>
);
}
Live preview, examples and props: https://keyframeui.com/components/exploded-ui#exploded-ui-design-system-demo






















