Your first themed page
End-to-end tutorial: install Crown, set data-brand and data-mode, build a button with semantic Tailwind utilities.
This tutorial builds one themed button end-to-end in about 5 minutes. By the end, the button re-colours live when you change data-brand or data-mode on <html> — no component changes, no page reload.
Prerequisites: a web project using Tailwind CSS v4.
1. Install
bun add @kingpowerclick/crown-css @kingpowerclick/crown-tailwind2. Import Crown's CSS
Add these imports to your global CSS entry (app/globals.css or equivalent):
@import 'tailwindcss';
@import '@kingpowerclick/crown-css/themes.css';
@import '@kingpowerclick/crown-tailwind';
@import '@kingpowerclick/crown-tailwind/theme.css';
@import '@kingpowerclick/crown-tailwind/variants.css';This registers Crown's colour, spacing, and radius tokens as Tailwind utilities and sets up brand/mode variants.
3. Set theme attributes on <html>
Crown resolves the active brand and mode from data-brand and data-mode attributes:
<html data-brand="kp" data-mode="light">In Next.js App Router, set them on the root layout:
// app/layout.tsx
export default function RootLayout({ children }: { children: React.ReactNode }) {
return (
<html lang="en" data-brand="kp" data-mode="light" suppressHydrationWarning>
<body>{children}</body>
</html>
)
}suppressHydrationWarning allows a pre-hydration script to update the attributes without React warning. See the Next.js guide for the full FOUC-safe setup.
4. Build a themed button
Crown's Tailwind utilities follow a {role}-{placement}-{state} naming pattern. A primary button uses:
| Utility | What it does |
|---|---|
bg-primary-foreground-default | Brand's primary fill colour |
text-on-primary-content-high | High-contrast label colour on that fill |
border-primary-border-default | Brand's primary stroke |
hover:bg-primary-foreground-hover | Fill on pointer hover |
rounded-cta-sm | Crown's CTA corner-radius token |
function PrimaryButton({ children }: { children: React.ReactNode }) {
return (
<button
className={[
'bg-primary-foreground-default',
'text-on-primary-content-high',
'border border-primary-border-default',
'rounded-cta-sm',
'px-4 py-2 text-sm font-medium',
'hover:bg-primary-foreground-hover',
'transition-colors',
].join(' ')}
>
{children}
</button>
)
}The component has no brand logic — it binds to roles. Crown does the rest.
5. Switch brand and mode
Change data-brand or data-mode and every Crown utility re-resolves:
// Switch to GWL brand
document.documentElement.dataset.brand = 'gwl'
// Switch to dark mode
document.documentElement.dataset.mode = 'dark'The same button now renders in GWL colours, in dark mode — zero component changes.
Crown's variants.css also provides conditional utilities you can apply only under a given brand or mode:
// Extra ring only on KP brand
<button className="bg-primary-foreground-default data-brand-kp:ring-2 data-brand-kp:ring-offset-1">
Buy now
</button>See the Tailwind guide for the full set of available variants.
What's next
- Tailwind guide — opacity modifiers, conditional variants, dark mode.
- Foundations → Color — browse all semantic roles and watch them re-resolve live.
- Concepts → Token layers — the six-layer pipeline that makes brand-switching work.