Skip to contentEnma

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 hint for 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 Switch for settings that apply immediately; Checkbox when 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-raised blocks with a slow shimmer, shown only after about 300ms. Never a full-screen spinner. Button loading for 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

  • Table with framed={false} inside a card, 13px text, right-aligned tabular numbers, status in a Badge.
  • Filters above the table: SegmentedControl for two to four ranges, TextField size="sm" with a search icon, sm buttons. One primary action at most ("New invoice").
  • KPI tiles: Stat with a sub line ("+12.4% this month"). Add a Sparkline when 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

  • TabBar for 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.

↑ ↓ to move, Enter to open, Esc to close

Keyboard shortcuts

Open the command palette
Ctrl then K
Search
/
Show keyboard shortcuts
?
Close the top overlay
Esc
Go to Home
G then H
Go to Themes
G then T
Go to Playground
G then P
Go to Components
G then C
Go to Guides
G then G
Go to Samples
G then S