Design system
Overview
A calm service page in every state: plain words, one big box, people to call, and nothing that looks like a startup landing page or a government website.
Whatever you need, start here
A picture of the big box, for this page only.
One box. Every public page offers one large box to describe what you need.
People to call are always close. Every footer says: In danger, call 911. In crisis, call or text 988.
One primary action per screen. Everything else is outline, quiet, or a link.
Tell the truth about state. Submitted only when the agency has it. Say what we cannot check.
Whitespace first, then hairlines, then cards. Cards only for things you can act on.
Safety by default. No sensitive text in addresses. Masked values.
Foundations
The tokens in app/globals.css, by what they are for. Every component on this page is built from these and nothing else.
Color roles
Each surface with its text, measured in your browser. Body text needs 4.5:1; every pair here passes.
Palette
Pine is the only solid color. Status colors appear only where status is the point, and always with words.
Surfaces
- Paper, the canvaspaper · #ffffff
- Paper 2, wells and the footerpaper-2 · #f3f4f6
- Frame, the gray hero panelframe · #eef0f3
Text
- Ink, titlesink · #14171c
- Ink 2, bodyink-2 · #2f3747
- Ink 3, muted (never lighter)ink-3 · #5b6271
Action
- Pine, the one solid colorpine · #0b2c63
- Pine 2, its hoverpine-2 · #133a7c
Lines and focus
- Line, hairlines between contentline · rgb(20 23 28 / 0.1)
- Field, the edge of what you type infield · #7c828c
- Ring, the focus outlinering · #3b6fd8
Status
- Leaf on moss, goodmoss · #e4f2ea / #17603c
- Amber on marigold soft, attentionmarigold-soft · #fdf1d8 / #7a4a00
- Marigold, dots and the door markmarigold · #f0b23e
- Brick on brick soft, bad newsbrick-soft · #fbe4dd / #a3341c
- Sky soft, neutral chipssky-soft · #e8eef8
Charts, by kind of help
- Chart 1chart-1 · #2a78d6
- Chart 2chart-2 · #eb6834
- Chart 3chart-3 · #1baf7a
- Chart 4chart-4 · #eda100
- Chart 5chart-5 · #e87ba4
- Chart 6chart-6 · #008300
- Chart 7chart-7 · #4a3aa7
- Otherchart-other · #a3a19a
- Muted, while one series is litchart-muted · #e3e5e9
Typography
Newsreader at weight 400 for titles, Inter for everything you read and press, Plex Mono for what you copy. Sentence case. No italics in headings, no uppercase labels.
| Token | Spec | Use | Specimen |
|---|---|---|---|
| home-title | Newsreader 400, 36 to 80px, 1.05, -0.02em | The national home's title | Whatever you need, start here |
| display-xl | Newsreader 400, 0.95, -0.05em | Big titles on the landings | Help that fits your life |
| PageHeader | Newsreader 400, 44px, 60px from 640px | Resident and public page titles | Renewal emails |
| ConsoleHeader | Newsreader 400, 40px, 48px from 640px | Agency console titles | Inbox |
| Section | Newsreader 400, 24px, 28px from 640px | Section titles on resident pages | Coming up |
| Card name | Newsreader 400, 22px | A place or program named on a card | Northside Community Pantry |
| Lead | Inter 400, 18px, 20px from 640px, ink-2 | The line under a page title | We fill in the agency's form. You read it and sign. |
| Body | Inter 400, 16px, 15px from 640px, ink-2 | Running text | Your Basic Food renewal is due November 22, 2026. |
| Label | Inter 500, 15px, ink | Field names and buttons | Email address |
| Small | Inter 400, 14px, ink-3 | Help under a field, table cells | We only use it to send renewal reminders. |
| Caption | Inter 400, 13px, ink-3 | Sources and checked dates | Listed on wa211.org, checked on October 10, 2026 |
| Mono | IBM Plex Mono 400, 15px | Masked numbers, reference numbers, links to copy | ***-**-4821 · localcarehub.org/r/maria |
We fill in the agency's form from your vault: your saved answers and documents. You read it and sign. When the agency has it, the status says Submitted, and not before. Every program page says where its answer comes from, like the Department of Social and Health Services, and when we last checked it. Reference numbers show in Plex Mono, like DSHS-2026-118204.
Spacing
Tailwind's 4px steps. Whitespace first, then hairlines, then cards.
- 1 · 4px
- 2 · 8px
- 3 · 12px
- 4 · 16px
- 6 · 24px
- 8 · 32px
- 10 · 40px
- 12 · 48px
- 16 · 64px
Inside a component · 8px (gap-2)
An icon and its label in a button
Between related items · 12 to 16px (gap-3, gap-4)
A field's label, box and help line; buttons in a row
Between groups · 24 to 32px (gap-6, gap-8)
Fields in a form; cards in a list
Between sections · 48px
Sections in a resident page's column (Section in Column)
Radius
Pills for what you press, 16px for what you type in, 24px for cards. Pinned in app/globals.css at Tailwind's own values.
- sm · 4pxCheckboxes, small marks in rows
- lg · 8pxSmall buttons inside tables
- xl · 12pxMenu and select rows, tooltips, sidebar rows
- 2xl · 16pxText fields and textareas, menus, popovers, toasts, alerts
- [1.25rem] · 20pxDialogs, sheets, the account sidebar
- 3xl · 24pxCards and wells
- [2.5rem] · 40pxHero frames
- full · pillButtons, selects, chips, toggles, the big box
Elevation
Four levels. Most things are flat; only what floats over the page has a shadow.
- FlatThe canvas, wells, the footer. Whitespace and hairlines do the work.
- HairlineCards: a 1px ring at 10% ink, no shadow.
- RaisedMenus, popovers, tooltips, toasts (shadow-lg).
- OverlayDialogs and sheets (shadow-overlay) over the page lightly blurred.
Motion
Short and calm: 150 to 300 ms, ease-out, crossfades, no bouncing. Reduced motion stops all of it.
- prompt-in240 msThe next example in the big box
- scene-fade300 msThe hero card's screens crossfading
- surface-in220 msA dialog, sheet or card fading in
- message-in260 msA new turn or answer block
- pill-in220, 50 apart msFollow-up pills
- fd-rise200, 150 apart msProgram cards arriving in the conversation
- Sheet, accordion200 msSliding in, opening a fold
- Toast300 msSliding up from the bottom
- Switch150 msThe knob moving across
Icons
A few inline marks in components/shadcn/icons.tsx, no icon package. 16px inside components, 20px in rows and the sidebar, always decorative.
16px ink
20px ink
20px ink-3
Actions
One primary action per screen. Everything else is outline, quiet, or a link.
Button
Pills. Pine is the only solid color. Button and LinkButton in components/ui.tsx draw from this same recipe, under their own names.
components/shadcn/button.tsx
| default | hover | focus | active | disabled | loading | |
|---|---|---|---|---|---|---|
| default | ||||||
| outline | ||||||
| secondary | ||||||
| ghost | ||||||
| destructive | ||||||
| link |
| components/ui.tsx | shadcn Button | When |
|---|---|---|
| primary | default | The one action on the screen |
| secondary | outline | Every other button |
| quiet | link | An action that reads as a link |
| danger | destructive | Reject, Deny, Withdraw |
| warn (deprecated) | default | Old code only; use primary or danger |
| sm, md, lg | sm, default, lg | Sizes |
Toggle and ToggleGroup
Two to five views of the same thing, like Weeks or Months. The picked one is white with a hairline ring.
components/shadcn/toggle-group.tsx
| default | hover | focus | active | disabled | |
|---|---|---|---|---|---|
| off | |||||
| on |
Badge
A word of status in its color: words and color together, never color alone.
components/shadcn/badge.tsx
A long badge truncates; put the full words in its title or the row.
Inputs
Labels always show, in sentence case. The edge of every field is the 3:1 field gray, darkening on hover and a 2px pine ring on focus.
Field
Every form control sits in a Field with its label, help and error. Problems are said in plain words under the box.
components/shadcn/field.tsx
We only use it to send renewal reminders.
Change it in Settings.
Please do not include Social Security, card or bank numbers. 0 of 2,000 characters.
| default | hover | focus | disabled | invalid | |
|---|---|---|---|---|---|
| input |
Select and NativeSelect
NativeSelect for plain choices on phones first (the phone's own picker). Select when rows need more than text. Pass items so the box shows the label.
components/shadcn/select.tsx · native-select.tsx
Checkbox, RadioGroup and Switch
A checkbox for a yes you confirm, radios for one choice of a few, a switch for a setting that takes effect at once.
components/shadcn/checkbox.tsx · radio-group.tsx · switch.tsx
Data display
Cards only for things you can act on. Lists are rows on hairlines.
Card
A white card with a hairline ring and 24px corners, for a task, a program or a place you can act on.
components/shadcn/card.tsx
Table
From 768px; phones get rows on hairlines. Counts under 10 read Under 10.
components/shadcn/table.tsx
| Program | Due | Status |
|---|---|---|
| Basic Food | Nov 22 | Due in 42 days |
| Apple Health | Jan 3, 2027 | In review |
| Working Families Tax Credit | Dec 31 | Submitted |
Avatar
A person is their initials on navy. A photo only when there is one.
components/shadcn/avatar.tsx
No photo: the initials show. The marigold dot means something needs the person.
Separator
The hairline between content. Whitespace first, then hairlines, then cards.
components/shadcn/separator.tsx
Mail it for me
Accordion
Folds on hairlines for what most people skip: the numbers behind a chart, the full calculator.
components/shadcn/accordion.tsx
Feedback
Say what happened in plain words, in the place it happened. No shimmer, and never a spinner on its own.
Alert
A callout line on a soft well. The color says what kind of news; the words always say it too.
components/shadcn/alert.tsx
toast
Only to confirm something the person just did. Anything they must read stays on the page.
components/shadcn/toast.tsx
Spinner
Inside a button that is working, with words. Never on its own as the only sign.
components/shadcn/spinner.tsx
Skeleton
The still shape of a card while it loads. It does not pulse.
components/shadcn/skeleton.tsx
Empty
A page with nothing in it yet. Inside a section, use one line between hairlines instead (EmptyLine).
components/shadcn/empty.tsx
Overlays
Each opens from a real button. Focus moves in, Escape closes, and focus goes back to the button.
Dialog
Sheet
Popover
Tooltip: names an icon button. Never the only place a fact lives.
DropdownMenu: 44px rows, Sign out in brick.
Do and don't
The rules in DESIGN.md that are easiest to break, side by side.
One primary action per screen. Everything else is outline, quiet, or a link.
Labels are sentence case. No uppercase eyebrows, no italics in headings.
For officials
Where people ask for help
For officials
Where people ask for help
Text plus color, never color alone.
The edge of a field is the field gray, 3:1 on every surface, so people can see where to type.
Recipes and an example screen
Front Door's own patterns, rebuilt from the components above.
Section with rows
Every /me page: a Newsreader heading, a link beside it, then rows on hairlines. Empty is one line.
components/ui.tsx: Section, SectionLink, Rows, EmptyLine
Coming up
All renewals- Basic Food renewalNov 22 · 42 days
- Apple Health renewalJan 3, 2027
Inbox
Nothing to read right now.
Subject to funds
On a program page above the buttons: marigold while money lasts, brick when it is closed, with the agency's own words.
FundsLine in components/ProgramAnswer.tsx
Example screen: a resident's tasks
Built only from tokens and components/shadcn. Sample values: Maria is the demo's made-up person.
Made-up person. Nothing here is sent.
Tasks
You have 2 things to do.
In danger, call 911. In crisis, call or text 988.
Inbox
Linked reports above a calm letter list. Sample letters, with no database or messages sent.
Letters and reports
Pick a report or tab, filter unread letters, and open a letter. Opening one marks it read in this example.
components/blocks/inbox
Letters
2 unread- Unread. DSHSPlease send your pay stubsPlease send your last 30 days of pay stubs by October 20 so we can finish reviewing your Basic Food application.
- Unread. HCAYour Apple Health coverage continuesYour Apple Health coverage has been renewed. You do not need to send anything else today.
- Jordan LeeYour rent receipt for OctoberHere is your receipt for October. Keep it with your other housing papers.
- Second HarvestFood pickup this weekOur food bank is open on Thursday from 10 AM to 2 PM. Bring a bag if you have one.
Open a sample letter to read it. These letters are examples, and nothing is sent.
Empty
No letters in the current view, with a plain next step.
Letters
0 unreadOpen a sample letter to read it. These letters are examples, and nothing is sent.
Loading
Still shapes hold the letter rows while the data loads.
Letters
Open a sample letter to read it. These letters are examples, and nothing is sent.