Guides
Migrating an existing Rook app
Measured starting point for every app: run monarch check and monarch registry verify on a checkout.
Each step is shippable on its own; nothing requires a rewrite.
Step 0: baseline (10 minutes)
npx monarch check --product <id> --write-baseline monarch.baseline.json,
commit it, add the reusable workflow. From now on new violations fail CI;
old ones are tracked.
Step 1: tokens under the existing UI (one PR, low risk)
- Install the packages and import the four CSS files
(
getting-started.md§2), includingcss/compat. - Delete the token blocks (
:root { --background … }and.dark { … }) fromglobals.css. Keep your utilities and app CSS, and keep any app-specific variables Monarch doesn't define (grepvar(--and check each one still resolves). Apps that use their brand colour for--accentneed--accent: var(--primary): the bridge mapsaccentto Rook Blue, as most Rook apps do. - Replace
tailwind.config.tscolour/radius/keyframe sections with the preset. Keepcontentand any app-specific plugins. - Add
appearanceScript({ product })to<head>, unless the app toggles the theme at runtime (see getting-started §3); then just set<html data-mn-product="<id>">. - Visual check in light and dark. Expected differences, all intentional:
stronger input borders, accessible primary fills (see the product's row in
contrast-report.json), consistent shadows. Note that the legacy--inputnow maps to Monarch'sborder-input(about 56% grey instead of 88%); the few places using it as a background (for example unchecked Switch tracks) get a darker track; switch them tobg-mutedor the Monarch Switch. Also expected:rounded-md/rounded-smare 8px/6px (were 10px/8px), anddestructiveis Rook Red rather than shadcn's generic red. - Gold and orange brands keep their fill as
--primarybecause they need dark text on it; usetext-mn-accent-strongfor accent-coloured text in those apps. Every other brand's--primaryis readable as text on every surface.
Conformance drops tokens/local-token-definitions to the few deliberate
overrides and deps/monarch-version to "current". registry verify reports
partial after this step (duplicate local components remain) and
adopted after Step 2. In the first migration, 63 local token variables
became 5, with 0 axe violations and at most 0.31% of pixels changed.
Step 2: components (incremental)
Swap components/ui/* for Monarch imports, one primitive at a time,
starting with Button, Field/Input, Dialog, DropdownMenu. Map:
| shadcn variant | Monarch |
|---|---|
default |
variant="primary" |
outline |
variant="secondary" (default) |
ghost |
variant="ghost" |
destructive |
variant="danger" |
size="icon" |
<IconButton label=… icon=… /> |
<Label> + <Input> + error <p> |
<Field><FieldLabel/><Input/><FieldError/></Field> |
Delete the local file once nothing imports it;
components/duplicated-primitive counts what is left.
Step 3: colours and type (ratchet)
Replace palette classes with mn-* classes or semantic legacy names,
guided by the report. Target: color/no-raw-palette = 0,
typography/no-arbitrary-type = 0. Legitimate literals (OG images, brand
logos, third-party colours) get a registry exception.
Step 4: remove the bridge
When legacy/bridge-variable is 0, drop css/compat. Done.
Rook platform notes
- Keep the shared Rook shell pieces (
RookRail, the theme toggle, the Space switcher and the chat dock) as they are; they already use the shared cookie andrail-expanded:variant. - Vite + Tailwind 3 apps follow the same steps.
- Tailwind 4 marketing sites: CSS files only, no preset.