--- name: ADS 3.0 Design System description: React component library implementing the NSW Department of Education's ADS 3.0 design language version: alpha colors: # Palette (do not reference directly in components) blue-01: "#002664" blue-02: "#146CFD" blue-03: "#69B3E7" blue-04: "#CBEDFD" blue-05: "#EBF5FF" red-01: "#3E0014" red-02: "#D7153A" red-03: "#F5C5D0" red-04: "#FDDDE5" red-05: "#FFF5F8" orange-01: "#7A3300" orange-02: "#EC6608" orange-03: "#F5B98A" orange-04: "#FEF0E4" green-01: "#005C35" green-02: "#00A651" green-03: "#89E5B3" green-04: "#E0F8EA" grey-01: "#22272B" grey-02: "#6D7278" grey-03: "#C0C0C0" grey-04: "#E0E0E0" off-white: "#F4F4F4" white: "#FFFFFF" # Semantic (use these in components) primary: "{colors.blue-02}" primary-dark: "{colors.blue-01}" error: "{colors.red-02}" success: "{colors.green-02}" warning: "{colors.orange-02}" text: "{colors.grey-01}" text-secondary: "{colors.grey-02}" border: "{colors.grey-04}" bg: "{colors.off-white}" surface: "{colors.white}" typography: h1: fontFamily: Public Sans Variable fontSize: 48px fontWeight: "700" lineHeight: 1.25 h2: fontFamily: Public Sans Variable fontSize: 32px fontWeight: "700" lineHeight: 1.25 h3: fontFamily: Public Sans Variable fontSize: 24px fontWeight: "600" lineHeight: 1.333 h4: fontFamily: Public Sans Variable fontSize: 20px fontWeight: "600" lineHeight: 1.4 h5: fontFamily: Public Sans Variable fontSize: 16px fontWeight: "600" lineHeight: 1.5 h6: fontFamily: Public Sans Variable fontSize: 14px fontWeight: "600" lineHeight: 1.43 intro: fontFamily: Public Sans Variable fontSize: 20px fontWeight: "400" lineHeight: 1.4 body: fontFamily: Public Sans Variable fontSize: 16px fontWeight: "400" lineHeight: 1.5 small: fontFamily: Public Sans Variable fontSize: 14px fontWeight: "400" lineHeight: 1.357 caption: fontFamily: Public Sans Variable fontSize: 12px fontWeight: "400" lineHeight: 1.5 rounded: sm: 4px DEFAULT: 6px lg: 10px xl: 16px full: 9999px spacing: unit: 4px scale: "Tailwind default (4px base: 1=4px, 2=8px, 3=12px, 4=16px, 6=24px, 8=32px)" components: button-primary-default: backgroundColor: "{colors.primary-dark}" textColor: "{colors.white}" typography: "{typography.body}" rounded: "{rounded.DEFAULT}" height: 48px button-primary-danger: backgroundColor: "{colors.red-02}" textColor: "{colors.white}" button-secondary-default: backgroundColor: transparent textColor: "{colors.primary-dark}" input: backgroundColor: "{colors.white}" textColor: "{colors.text}" typography: "{typography.body}" rounded: "{rounded.DEFAULT}" height: 48px card-surface: backgroundColor: "{colors.surface}" rounded: "{rounded.xl}" badge-info: backgroundColor: "{colors.blue-02}" textColor: "{colors.white}" rounded: "{rounded.full}" alert-info: backgroundColor: "{colors.blue-05}" rounded: "{rounded.DEFAULT}" --- ## Overview ADS 3.0 (Adaptive Design System) is a React component library based on the NSW Department of Education's digital design language. It uses Public Sans as its typeface, a structured blue/grey palette with semantic colour aliases, and consistent border radii and spacing. Components are built with React 19, TypeScript (strict), and Tailwind CSS v4. All visual values come from design tokens defined in `src/tokens/tokens.css`. Components never use raw colour values — they reference semantic or domain-specific token classes via Tailwind utilities. ## Colors The palette is organised in three layers: 1. **Palette** — Raw values (`blue-01` through `blue-05`, `grey-01` through `grey-04`, etc.). Never use these directly in component code. 2. **Semantic** — Purpose-based aliases (`primary`, `error`, `success`, `warning`, `text`, `surface`, `bg`, `border`). Use these for general UI. 3. **Domain** — Component-specific tokens (`button-default`, `control-border`, `badge-info`, `alert-error-bg`, `tag-navy`, etc.). Use these within their respective components. The primary brand colour is `blue-01` (#002664, dark navy) for interactive elements like buttons and links. `blue-02` (#146CFD) is the brighter accent used for info states, focus rings, and highlights. ## Typography The system uses **Public Sans Variable** (loaded via `@fontsource-variable/public-sans`). The type scale runs from `caption` (12px) to `h1` (48px). Headings use weight 600–700; body text uses 400. Use Tailwind's `text-{scale}` utilities: `text-h1`, `text-h2`, `text-h3`, `text-h4`, `text-h5`, `text-h6`, `text-intro`, `text-body`, `text-small`, `text-caption`. ## Layout & Spacing Spacing follows Tailwind's default 4px base scale. Common values: - `p-2` (8px), `p-3` (12px), `p-4` (16px), `p-6` (24px) for padding - `gap-2` (8px), `gap-3` (12px), `gap-4` (16px) for flex/grid gaps - `space-y-4` (16px) for stacked content No custom spacing tokens are defined — the Tailwind defaults are sufficient. This may change in future. ## Elevation & Depth Two shadow levels: - `shadow-default` — subtle lift for cards and surfaces (`0 1px 3px rgba(0,0,0,0.08)`) - `shadow-md` — elevated elements like dropdowns and dialogs (`0 4px 6px -1px rgba(0,0,0,0.1)`) ## Shapes Border radii use the custom scale: - `rounded-sm` (4px) — small elements, tags - `rounded-default` (6px) — buttons, inputs, alerts - `rounded-lg` (10px) — cards, dialogs - `rounded-xl` (16px) — large containers - `rounded-full` (9999px) — badges, circular buttons ## Components ### Button Interactive button with variant/intent/size matrix. | Prop | Type | Default | Description | |------|------|---------|-------------| | `variant` | `'primary' \| 'secondary' \| 'tertiary'` | `'primary'` | Visual weight | | `intent` | `'default' \| 'danger' \| 'subtle' \| 'neutral'` | `'default'` | Semantic purpose | | `size` | `'default' \| 'comfortable' \| 'compact'` | `'default'` | Height and padding | | `loading` | `boolean` | `false` | Shows spinner, disables interaction | | `leftIcon` | `ReactNode` | — | Icon before label | | `rightIcon` | `ReactNode` | — | Icon after label | ```tsx import { Button } from '@/components/atoms/Button' ``` ### IconButton Icon-only button with required `aria-label`. | Prop | Type | Default | Description | |------|------|---------|-------------| | `variant` | `'primary' \| 'secondary' \| 'tertiary'` | `'primary'` | Visual weight | | `intent` | `'default' \| 'danger' \| 'neutral'` | `'default'` | Semantic purpose | | `size` | `'default' \| 'large' \| 'compact' \| 'small' \| 'xsmall'` | `'default'` | Button dimensions | | `shape` | `'circle' \| 'square'` | `'circle'` | Border radius | | `icon` | `ReactNode` | — | **Required.** The icon element | | `aria-label` | `string` | — | **Required.** Accessible label | ```tsx import { IconButton } from '@/components/atoms/IconButton' import { X, Settings } from 'lucide-react' } aria-label="Close" variant="tertiary" /> } aria-label="Settings" shape="square" size="compact" /> ``` ### Input Text input with label, description, hint, error, and icon slots. | Prop | Type | Default | Description | |------|------|---------|-------------| | `label` | `string` | — | **Required.** Visible label | | `description` | `string` | — | Help text below label | | `hint` | `string` | — | Inline hint (right-aligned) | | `error` | `string` | — | Error message (replaces description) | | `variant` | `'outlined' \| 'stacked'` | `'outlined'` | Label position | | `size` | `'default' \| 'compact'` | `'default'` | Input height | | `leftIcon` | `ReactNode` | — | Icon inside input (left) | | `rightIcon` | `ReactNode` | — | Icon inside input (right) | ```tsx import { Input } from '@/components/atoms/Input' import { Search, Mail } from 'lucide-react' } /> } /> ``` ### Textarea Multi-line text input with optional auto-resize. | Prop | Type | Default | Description | |------|------|---------|-------------| | `label` | `string` | — | **Required.** Visible label | | `description` | `string` | — | Help text below label | | `hint` | `string` | — | Inline hint | | `error` | `string` | — | Error message | | `variant` | `'outlined' \| 'stacked'` | `'outlined'` | Label position | | `resize` | `'vertical' \| 'horizontal' \| 'both' \| 'none'` | `'vertical'` | Resize handle | | `autoResize` | `boolean` | `false` | Auto-grow with content | ```tsx import { Textarea } from '@/components/atoms/Textarea'