UI and UX patterns
Components are the words; these patterns are the sentences. Each one follows the core rules: one hero per screen, one accent spark per view, one primary button per view.
Layout
- Mobile screens: a 16px gutter, 12px between cards, 24px between sections. Top to bottom: a small eyebrow and title, the hero, the content, the primary action, the tab bar.
- Desktop apps: a sidebar at 1024px and up (240 to 260px), a top bar with search and the primary action, content in a 12-column grid with 16 to 24px gaps. Keep reading text at 60 to 75 characters.
- One hero per screen. On a dashboard, the hero is the one number the screen exists for (MRR, balance, weekly volume); the rest are KPI tiles in a row.
- Group with tone, not lines. Raised panels inside surface cards. Borders and dividers only between rows and table cells.
Forms
- One column, labels above fields, the primary action at the end and full width on mobile.
- Real placeholders ("Acme Labs"), never "e.g." or the label again. Use
hintfor format rules ("Shown on invoices."). - Validate on blur and on submit, not on every keystroke. The error replaces the hint and says what to do: "Enter a full email address."
- On submit with errors, move focus to the first invalid field.
- Use
Switchfor settings that apply immediately;Checkboxwhen there is a Save button. - Destructive actions use
Button variant="danger"and say what they destroy: "Delete workspace".
Empty, loading and error states
- Empty is an invitation: a title that names the space, one line of why, one primary action.
tsx
<Card padding="lg">
<div className="e-title">Log your first workout</div>
<p className="e-caption">Your weekly volume and personal records show up here.</p>
<Button variant="primary">Start workout</Button>
</Card>
- Loading: skeletons shaped like the content,
--e-raisedblocks with a slow shimmer, shown only after about 300ms. Never a full-screen spinner.Button loadingfor a single action. - Error: one sentence (what happened, what to do), a retry, and whatever data is already on screen stays there. Use
Toast tone="negative"for errors after an action; put blocking errors inline. - Offline: show cached content marked as stale ("Updated 2 hours ago"), queue writes, sync later.
Data-dense screens
Tablewithframed={false}inside a card, 13px text, right-aligned tabular numbers, status in aBadge.- Filters above the table:
SegmentedControlfor two to four ranges,TextField size="sm"with a search icon,smbuttons. One primary action at most ("New invoice"). - KPI tiles:
Statwith asubline ("+12.4% this month"). Add aSparklinewhen the trend matters more than the exact number. - Keyboard: J and K move through rows, Enter opens,
/focuses search, Cmd/Ctrl+K opens the palette. See the analytics sample. - More than about 100 rows: virtualize. More than 7 columns: hide the rest behind a row detail view.
Mobile navigation
TabBarfor three to five top-level destinations, always with labels. Never an action ("New") in the tab bar; put it on the screen as the primary button.- Push detail screens with a back button at the top left; respect the iOS swipe and the Android back button.
- Sheets for short tasks that keep context (pick a recipient, confirm an amount), full screens for long ones.
- Thumb zone: the primary action sits at the bottom, full width,
size="lg".
Writing
See Writing UI copy for the voice rules and examples.