Skip to content

Guides

Getting started

In a few steps you can have Monarch running in your app: light and dark themes, your brand colour, and accessible components that already feel at home together. Monarch works the same in a weekend project and a large product team. These steps assume React 18 or 19; the tokens alone work with any framework.

1. Install

npm i @rookcom/monarch-tokens @rookcom/monarch-react

Packages are public on npm, so npm ci works in every Docker build and CI job with no .npmrc or token. Pin exact versions (npm i -E) and upgrade by PR.

2. Load styles once, in the root layout

import '@rookcom/monarch-tokens/css'; // tokens, all themes
import '@rookcom/monarch-tokens/css/base'; // optional: body, focus ring, reduced motion
import '@rookcom/monarch-tokens/css/products/<id>'; // your accent (ids: registry/products)
import '@rookcom/monarch-react/styles.css'; // component styles

Order does not matter: every file declares the cascade-layer order.

3. Apply the appearance before paint

import { appearanceScript } from '@rookcom/monarch-tokens/appearance';

<html suppressHydrationWarning>
  <head>
    <script dangerouslySetInnerHTML={{ __html: appearanceScript({ product: '<id>' }) }} />
  </head>

It reads the shared rook_theme cookie (light | dark | system) and the mn_contrast cookie, and sets data-mn-theme, data-mn-contrast, data-mn-product and the .dark class on <html>. Existing theme-toggle code keeps working as long as it writes the same cookie.

Rook apps scope dark mode to signed-in routes with <html data-rook-theme-routes="^/(w|home)(/|$)">; the script honours it, so public pages stay light. It replaces an app's own theme boot script; keep your theme toggle (it must write the same cookie).

If the app also changes the theme at runtime (for example a store or effect that toggles .dark after hydration, as a custom ThemeEffect might), don't add this script yet: it sets data-mn-theme, which that code won't clear. Keep the app's own boot script and only set <html data-mn-product="<id>">; Monarch's CSS follows .dark either way.

4. Tailwind (3.4)

import monarch from '@rookcom/monarch-tokens/tailwind';
export default { presets: [monarch], content: ['./src/**/*.{ts,tsx}'] };

You get bg-mn-surface, text-mn-fg-muted, border-mn-line, bg-mn-accent-solid, text-mn-success-strong, shadow-mn-md, h-control-md, duration-fast, rail-expanded: and the legacy bg-primary / text-muted-foreground names.

The preset is typed to be assignable to Tailwind 3's Config, so no cast is needed (fixed in tokens 0.2.2). Tailwind 4 or no Tailwind: skip this step; the CSS files are enough.

5. Use components

import { Button, Field, FieldLabel, Input, FieldError } from '@rookcom/monarch-react';

<Field invalid={!!error}>
  <FieldLabel>Email</FieldLabel>
  <Input type="email" value={v} onChange={…} />
  <FieldError>{error}</FieldError>
</Field>
<Button variant="primary" type="submit" loading={saving}>Save</Button>

Wrap the app in <TooltipProvider> once if you use tooltips.

6. Check conformance

Install the CLI in the app (npm i -D -E @rookcom/monarch-conformance), then use npx monarch … from the app root. Without the package installed, npx monarch would fetch an unrelated public package of the same name.

npx monarch check --product <id>            # text report
npx monarch check --product <id> --write-baseline monarch.baseline.json

Then add the reusable workflow (see docs/guides/conformance.md).