Westy Design Systemv0.2.7
OverviewComponentsExamplesStorybook

Foundations

  • Typography
  • Colors
  • Spacing
  • Radius
  • Shadows
  • Icons

Components

  • Accordion
  • Alert
  • Alert Dialog
  • Aspect Ratio
  • Avatar
  • Badge
  • Breadcrumb
  • Button
  • Button Group
  • Calendar
  • Card
  • Carousel
  • Chart
  • Checkbox
  • Collapsible
  • Combobox
  • Command
  • Context Menu
  • Data Table
  • Date Picker
  • Dialog
  • Direction
  • Drawer
  • Dropdown Menu
  • Empty
  • Field
  • Hover Card
  • Input
  • Input Group
  • Input OTP
  • Item
  • Kbd
  • Label
  • Menubar
  • Native Select
  • Navigation Menu
  • Pagination
  • Popover
  • Progress
  • Questionnaire
  • Radio Group
  • Resizable
  • Scroll Area
  • Select
  • Separator
  • Sheet
  • Sidebar
  • Skeleton
  • Slider
  • Sonner
  • Spinner
  • Switch
  • Table
  • Tabs
  • Textarea
  • Toggle
  • Toggle Group
  • Tooltip

Chat

  • Attachment
  • Bubble
  • Marker
  • Message
  • Message Scroller

Foundations

Colors

A beige neutral scale with a green brand primary, orange in support, a purple ramp for data and a functional red for errors. Color reaches a component only through semantic tokens — bg-background, text-muted-foreground, border-border — never as a literal value.

Semantic tokens
The styling API — 31 tokens defined in globals.css, once in :root and again in .dark. Values resolve through the raw scales; hover a value to see the declaration as written.

basePage canvas & default text

  • --backgroundoklch(0.9512 0.0121 96.4253)
  • --foregroundoklch(0.2435 0 0)

cardElevated surfaces

  • --cardoklch(1 0 0)
  • --card-foregroundoklch(0.2435 0 0)

popoverFloating surfaces

  • --popoveroklch(1 0 0)
  • --popover-foregroundoklch(0.2435 0 0)

primaryBrand green — main actions

  • --primaryoklch(0.5904 0.1251 139.9147)
  • --primary-foregroundoklch(0.9855 0.0174 131.869)

secondaryBrand orange — supporting

  • --secondaryoklch(0.6933 0.2058 42.8784)
  • --secondary-foregroundoklch(0.9846 0.0124 75.3692)

mutedSubdued surfaces & text

  • --mutedoklch(0.9725 0.0067 97.3514)
  • --muted-foregroundoklch(0.5328 0.0463 96.9201)

accentHover & selection

  • --accentoklch(0.9725 0.0067 97.3514)
  • --accent-foregroundoklch(0.359 0.0344 96.3589)

destructiveErrors & irreversible actions

  • --destructiveoklch(0.577 0.245 27.325)

border / input / ringHairlines, fields & focus

  • --borderoklch(0.8657 0.0249 96.6167)
  • --inputoklch(0.8657 0.0249 96.6167)
  • --ringoklch(0.7803 0.0376 96.8081)

chartsData visualization ramp

  • --chart-1oklch(0.7803 0.0589 312.8)
  • --chart-2oklch(0.6254 0.1002 313)
  • --chart-3oklch(0.5062 0.1307 313.4)
  • --chart-4oklch(0.4505 0.142 311.7)
  • --chart-5oklch(0.4004 0.1307 311.3)

sidebarSidebar surfaces & accents

  • --sidebaroklch(0.985 0.0041 91.4457)
  • --sidebar-foregroundoklch(0.2435 0 0)
  • --sidebar-primaryoklch(0.5241 0.107 140.7839)
  • --sidebar-primary-foregroundoklch(0.9855 0.0174 131.869)
  • --sidebar-accentoklch(0.9725 0.0067 97.3514)
  • --sidebar-accent-foregroundoklch(0.359 0.0344 96.3589)
  • --sidebar-borderoklch(0.9512 0.0121 96.4253)
  • --sidebar-ringoklch(0.7803 0.0376 96.8081)
The pair convention
Every surface token pairs with a -foreground counterpart for the content on it — the background suffix is omitted on the surface, so bg-primary goes with text-primary-foreground. The blocks below are painted with the live tokens; press D to watch every pair remap to its dark values.

Aa

bg-background
text-foreground

Aa

bg-card
text-card-foreground

Aa

bg-popover
text-popover-foreground

Aa

bg-primary
text-primary-foreground

Aa

bg-secondary
text-secondary-foreground

Aa

bg-muted
text-muted-foreground

Aa

bg-accent
text-accent-foreground

Aa

bg-destructive/10
text-destructive

destructive is the one token without a -foreground pair — components tint it instead, a translucent bg-destructive/10 surface under text-destructive, so errors read loudly without a solid red slab.

Raw scales
The raw material — five scales running 50 → 950, parsed straight from the tokens in globals.css. Components never reference a raw step directly: the semantic tokens above map to them and remap automatically between light and dark.
@theme

greenBrand primary

  • --color-green-50oklch(0.9855 0.0174 131.869)
  • --color-green-100oklch(0.9541 0.0347 129.4029)
  • --color-green-200oklch(0.8959 0.0613 131.4145)
  • --color-green-300oklch(0.811 0.1053 135.5721)
  • --color-green-400oklch(0.6933 0.1222 138.0136)
  • --color-green-500oklch(0.5904 0.1251 139.9147)
  • --color-green-600oklch(0.5241 0.107 140.7839)
  • --color-green-700oklch(0.4581 0.0844 140.6847)
  • --color-green-800oklch(0.3761 0.0672 140.2235)
  • --color-green-900oklch(0.3299 0.0536 141.3419)
  • --color-green-950oklch(0.2233 0.0367 141.7116)

beigeNeutral scale

  • --color-beige-50oklch(0.985 0.0041 91.4457)
  • --color-beige-100oklch(0.9725 0.0067 97.3514)
  • --color-beige-200oklch(0.9512 0.0121 96.4253)
  • --color-beige-300oklch(0.8657 0.0249 96.6167)
  • --color-beige-400oklch(0.7803 0.0376 96.8081)
  • --color-beige-500oklch(0.7036 0.0535 96.335)
  • --color-beige-600oklch(0.6182 0.0499 96.6275)
  • --color-beige-700oklch(0.5328 0.0463 96.9201)
  • --color-beige-800oklch(0.4254 0.0392 98.1981)
  • --color-beige-900oklch(0.359 0.0344 96.3589)
  • --color-beige-950oklch(0.2435 0 0)

orangeBrand secondary

  • --color-orange-50oklch(0.9846 0.0124 75.3692)
  • --color-orange-100oklch(0.957 0.034 77.213)
  • --color-orange-200oklch(0.9009 0.0713 71.648)
  • --color-orange-300oklch(0.8331 0.1223 66.1577)
  • --color-orange-400oklch(0.741 0.1763 53.256)
  • --color-orange-500oklch(0.6933 0.2058 42.8784)
  • --color-orange-600oklch(0.6353 0.2145 37.0344)
  • --color-orange-700oklch(0.5438 0.1884 34.5898)
  • --color-orange-800oklch(0.4622 0.1517 33.6008)
  • --color-orange-900oklch(0.4012 0.1188 34.3827)
  • --color-orange-950oklch(0.2616 0.0763 32.6596)

purpleCharts & data viz

  • --color-purple-50oklch(0.9858 0.0073 312.3)
  • --color-purple-100oklch(0.9433 0.0166 312.6)
  • --color-purple-200oklch(0.883 0.0314 312.7)
  • --color-purple-300oklch(0.7803 0.0589 312.8)
  • --color-purple-400oklch(0.6254 0.1002 313)
  • --color-purple-500oklch(0.5062 0.1307 313.4)
  • --color-purple-600oklch(0.4505 0.142 311.7)
  • --color-purple-700oklch(0.4004 0.1307 311.3)
  • --color-purple-800oklch(0.3536 0.1075 313.2)
  • --color-purple-900oklch(0.3076 0.0868 314.5)
  • --color-purple-950oklch(0.2349 0.0735 312.2)

redErrors & destructive

  • --color-red-50oklch(0.971 0.013 17.38)
  • --color-red-100oklch(0.936 0.032 17.717)
  • --color-red-200oklch(0.885 0.062 18.334)
  • --color-red-300oklch(0.808 0.114 19.571)
  • --color-red-400oklch(0.704 0.191 22.216)
  • --color-red-500oklch(0.637 0.237 25.331)
  • --color-red-600oklch(0.577 0.245 27.325)
  • --color-red-700oklch(0.505 0.213 27.518)
  • --color-red-800oklch(0.444 0.177 26.899)
  • --color-red-900oklch(0.396 0.141 25.723)
  • --color-red-950oklch(0.258 0.092 26.042)
Adding a color
A new token lands in three places, all in globals.css: a light value in :root, its dark counterpart in .dark, and an @theme inline mapping that turns it into Tailwind utilities. Skip any one of the three and the color is either unreadable in one theme or invisible to Tailwind.
:root {
  --success: var(--color-green-600);
}

.dark {
  --success: var(--color-green-400);
}

@theme inline {
  --color-success: var(--success);
}

/* bg-success, text-success and border-success now exist */
<p className="text-success">Transfer complete</p>