Crown Design
Getting Started

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-tailwind

2. 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:

UtilityWhat it does
bg-primary-foreground-defaultBrand's primary fill colour
text-on-primary-content-highHigh-contrast label colour on that fill
border-primary-border-defaultBrand's primary stroke
hover:bg-primary-foreground-hoverFill on pointer hover
rounded-cta-smCrown'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

On this page