Tailwind for developers
Tokens, not hex codes
North ships Tailwind themes generated from the same token file as everything else. Install them once and use brand classes: bg-n-action, text-n-heading, rounded-lg, shadow-2, text-heading-1. Hex codes in class names (bg-[#227ED1]) are a code-review failure.
Tailwind v4
/* app.css */
@import "tailwindcss";
@import "./north-tokens.css"; /* CSS variables: primitives + light/dark semantic roles */
@import "./north-tailwind.css"; /* @theme: brand palette, type styles, radius, shadows, motion */- The default Tailwind palette is removed (
--color-*: initial): only brand colours exist, so off-brand colours fail at build time. - The
dark:variant follows both the OS setting and<html data-theme="dark">, like the hub. With semantic classes you rarely need it. - Spacing uses a 4px base (
--spacing: 4px):p-4= 16px,gap-6= 24px, matching--n-space-*.
Tailwind v3
// tailwind.config.js
module.exports = {
presets: [require('./tailwind.preset.cjs')],
content: ['./src/**/*.{html,js,jsx,ts,tsx}'],
};
/* and load north-tokens.css globally: semantic colours read its variables */Class names are identical in v3 and v4. In v3, opacity modifiers (/20) don't work on semantic colours because they are CSS variables; use the primitive colour instead (bg-gulf-70/20).
What the theme provides
| Group | Classes | Source tokens |
|---|---|---|
| Semantic colours (switch light/dark) | bg-n-canvas bg-n-subtle bg-n-panel bg-n-surface-raised text-n-heading text-n-body text-n-caption text-n-link bg-n-action hover:bg-n-action-hover text-n-on-action border-n-border border-n-border-ui outline-n-focus bg-n-skeleton-base bg-n-scrim bg-n-table-header and all n-diagram-* | semantic.* |
| Brand palette | midnight-05…95 dune-02…95 dawn-* oasis-* gulf-* steel-* snow white black status-* | color.* |
| Chart series | dataviz-1…6 | color.dataviz.* |
| Fonts | font-display font-text font-arabic font-mono (font-sans = text) | font.family.* |
| Text styles | text-display-xl text-display-lg text-heading-1…4 text-lead text-body-lg text-body text-body-sm text-caption text-microtitle text-code (size + line height + tracking + weight) | typography.* |
| Radius | rounded-xs sm md lg xl 2xl full | radius.* |
| Shadows | shadow-1 shadow-2 shadow-3 shadow-4 shadow-glow | shadow.* |
| Breakpoints | sm: 640 · md: 960 · lg: 1280 · xl: 1600 | breakpoint.* |
| Motion | ease-standard ease-enter ease-exit ease-rise duration-instant/fast/base/slow/deliberate, animate-shimmer animate-dot animate-glow animate-rise animate-indeterminate animate-skel-pulse | motion.* |
| Sizes | h-control-sm/md/lg min-h-touch min-w-touch max-w-measure max-w-content | size.*, grid.* |
| Effects | blur-scrim blur-sm blur-md blur-lg backdrop-blur-scrim backdrop-blur-sm backdrop-blur-md | filter.* |
| Gradients | bg-aurora bg-horizon bg-night | gradient.* |
Component recipes
Class strings that reproduce the North components. The specs and states are on the component pages (Buttons, Forms, Tables, Feedback). If your project allows plain CSS, north-components.css gives you all of them as .n-* classes.
Primary button
Secondary button
Danger button
Icon button
Text input
Label
Hint
Badge (success)
AI badge
Filter chip (selected)
Card
Interactive card
Underline tab (active)
Table header cell
Table number cell
Alert (danger)
Toast
Skeleton line
Spinner
Agent pulse
Dialog
Scrim
Floating image button
Code block
Page heading
Body
Hero section
Using @apply for repeated components
/* v4 */
@layer components {
.btn-primary { @apply inline-flex items-center gap-2 h-control-md px-4 rounded-sm bg-n-action text-n-on-action font-medium hover:bg-n-action-hover; }
}Prefer real components (React, Vue, web components) over @apply for anything with logic. Keep one implementation per component in each product.
Rules for code review
- No arbitrary colour values (
bg-[#…],text-[rgb(…)]). If a colour is missing, ask for a token. - No raw pixel spacing outside the 4px scale (
p-[13px]). Arbitrary values are fine for one-off layout sizes, not for brand values. - Use semantic classes (
bg-n-*,text-n-*) in components; primitives (bg-midnight-80) only in brand artwork. - Every interactive element has
focus-visible:styles. - Respect motion preferences: pair
animate-*withmotion-reduce:animate-nonewhere the animation is decorative. - Arabic: use logical utilities (
ps-4 pe-4 ms-auto start-0 text-start) instead of left/right.
Dos and don'ts
Do
- Import the generated theme; never copy values by hand.
- Use semantic classes in components.
- Use logical (start/end) utilities for RTL.
- Regenerate when tokens change (npm run tokens).
Don't
- Re-enable the default Tailwind palette.
- Use arbitrary hex values.
- Use dark: overrides where a semantic class exists.
- Fork the theme per product.
Last updated on 14 October 2026