Grove
A design system for Twig — token-driven, accessible, and built for product teams. This site uses the brand intent on <html> so colours follow Grove semantic tokens (sprout active surfaces and pebble neutrals). React sources live under packages/grove/src in four layers (seeds → sprouts → branches → canopies). Everything is exported from @twig/grove.
Getting started
Import @twig/grove/css for the global reset, design tokens, typography utilities, and UI styles in one file. For smaller bundles, load granular sheets (for example @twig/grove/css/button) instead of the full bundle.
// globals.css
@import '@twig/grove/css'; /* reset + tokens + typography + UI */
@import '@twig/utils/css'; /* utility classes */// layout.tsx — brand intent drives semantic colours site-wide
<html data-theme="light" data-intent="brand">
...
</html>Component library
Each tier builds on the last. Import components by name from @twig/grove; source files are grouped by tier only for maintenance — there is no separate subpath import.
Seeds
Primitive controls — buttons, inputs, chips, links.
packages/grove/src/seeds
Exported: Badge, Button, Checkbox, Chip, Input, Link, ProgressBar, Radio, Select, Toggle
Sprouts
Composed patterns built from seeds — labelled fields and grouped inputs.
packages/grove/src/sprouts
Exported: AmountInput, CheckboxGroup, FormField, RadioGroup, SearchInput, ToggleRow
Branches
Product-shaped composites — rows and cards for money workflows.
packages/grove/src/branches
Exported: ExpenseRow, GoalCard, InsightCard, TransactionRow
Canopies
Layout shells that wrap flows — tab chrome and sheets.
packages/grove/src/canopies
Exported: SheetLayout, TabLayout
Token architecture
Grove uses a three-tier token hierarchy. Primitive values live in units.json and themes.json, semantic intent tokens map onto those primitives, and component tokens reference the semantic layer. This means swapping an intent changes colours everywhere that intent is applied.
units.json → --units-4: 4px
themes.json → --sprout-500: #6ba53d
intent.json → --surface-active-strong: var(--sprout-400)
components.json → --sprouts-button-color-primary-surface-default: var(--surface-active-strong)