Prism
← All primitives

TokenSwap

Theming

Set data-brand on any wrapper and every descendant re-skins instantly via CSS variables, with a filmic crossfade. One mechanism, unlimited themes.

Requires the --bx-* token palettes and [data-brand] blocks from globals.css — copy them into your own global stylesheet (they are not bundled in the manifest).

$npx shadcn@latest add https://prism.icglabs.co/r/token-swap.json
View raw manifest →

components/prism/TokenSwap.tsx
"use client";

import { useState } from "react";

/**
 * TokenSwap — the highest-leverage internal tool here. Set `data-brand` on any
 * wrapper and every descendant that reads the `--bx-*` CSS variables re-skins
 * instantly, with a filmic crossfade. One mechanism = unlimited themes. Ported
 * from Snupix's brand explorer. The six palettes live in globals.css.
 */
const BRANDS: { id: string; label: string }[] = [
  { id: "prism", label: "Prism" },
  { id: "golden", label: "Golden" },
  { id: "noir", label: "Noir" },
  { id: "romance", label: "Romance" },
  { id: "studio", label: "Studio" },
  { id: "neon", label: "Neon" },
];

export function TokenSwap() {
  const [brand, setBrand] = useState("prism");

  return (
    <div className="w-full">
      <div className="mb-5 flex flex-wrap gap-2">
        {BRANDS.map((b) => (
          <button
            key={b.id}
            onClick={() => setBrand(b.id)}
            className={`rounded-full border px-3.5 py-1.5 text-sm transition-colors ${
              brand === b.id
                ? "border-ink/40 bg-ink/10 text-ink"
                : "border-line text-muted hover:border-line-2 hover:text-ink"
            }`}
          >
            {b.label}
          </button>
        ))}
      </div>

      {/* Everything below re-skins from the data-brand tokens */}
      <div
        data-brand={brand}
        className="grain relative overflow-hidden rounded-2xl p-6 sm:p-8"
        style={{ background: "var(--bx-bg)", border: "1px solid var(--bx-line)" }}
      >
        <div className="flex flex-col gap-5 sm:flex-row sm:items-stretch">
          {/* Mock product card */}
          <div
            className="flex-1 rounded-xl p-5"
            style={{ background: "var(--bx-surface)", border: "1px solid var(--bx-line)" }}
          >
            <div className="mb-4 h-28 w-full rounded-lg" style={{ background: "var(--bx-grad)" }} />
            <div
              className="mb-2 text-xs font-medium uppercase tracking-widest"
              style={{ color: "var(--bx-acc)" }}
            >
              New release
            </div>
            <div className="mb-1 text-xl font-semibold" style={{ color: "var(--bx-ink)" }}>
              The same markup, six brands
            </div>
            <p className="mb-4 text-sm" style={{ color: "var(--bx-sub)" }}>
              Not a single class changed between themes — only the token layer.
            </p>
            <div className="flex items-center gap-2">
              <button
                className="rounded-lg px-4 py-2 text-sm font-medium"
                style={{ background: "var(--bx-acc)", color: "var(--bx-acc-ink)" }}
              >
                Primary action
              </button>
              <button
                className="rounded-lg px-4 py-2 text-sm font-medium"
                style={{ border: "1px solid var(--bx-line)", color: "var(--bx-ink)" }}
              >
                Secondary
              </button>
            </div>
          </div>

          {/* Token swatches */}
          <div
            className="flex w-full flex-col justify-between rounded-xl p-5 sm:w-56"
            style={{ background: "var(--bx-surface)", border: "1px solid var(--bx-line)" }}
          >
            <div className="text-xs font-medium uppercase tracking-widest" style={{ color: "var(--bx-sub)" }}>
              Tokens
            </div>
            <div className="grid grid-cols-4 gap-2 py-4">
              {["--bx-bg", "--bx-surface", "--bx-ink", "--bx-sub", "--bx-line", "--bx-acc", "--bx-acc-ink", "--bx-acc2"].map(
                (v) => (
                  <div
                    key={v}
                    title={v}
                    className="aspect-square rounded-md"
                    style={{ background: `var(${v})`, border: "1px solid var(--bx-line)" }}
                  />
                )
              )}
            </div>
            <code className="text-xs" style={{ color: "var(--bx-sub)" }}>
              data-brand=&quot;{brand}&quot;
            </code>
          </div>
        </div>
      </div>
    </div>
  );
}
Live demo — read-only. Every section is a real, copyable primitive.