Skip to contentEnma

Engineering standards

Enma makes screens look right. These standards make them work right. They apply to every project built with Enma, on every platform, and a screen isn't done until it meets them.

Performance

Targets (web, measured at the 75th percentile of real users): Largest Contentful Paint under 2.5s, Interaction to Next Paint under 200ms, Cumulative Layout Shift under 0.1.

  • JavaScript: keep the first-load bundle of an app shell under about 150 KB gzipped. Split by route, lazy-load heavy views (charts, editors, maps), and check the bundle with an analyzer before each release.
  • Fonts: only the active theme's families, woff2, font-display: swap, Latin subset, self-hosted (next/font, @fontsource or local files). Preload the display face only if it appears above the fold.
  • Images: AVIF or WebP, explicit width and height (or aspect-ratio) to prevent layout shift, loading="lazy" below the fold, responsive srcset.
  • Rendering: animate only transform and opacity (all Enma motion does). Virtualize lists longer than about 100 rows (TanStack Virtual on web, FlashList on native). Don't re-render whole screens on every keystroke: keep state local and memoize expensive children; turn on the React Compiler where the stack supports it.
  • Data: show cached data first and revalidate in the background; never block a whole screen on one slow request.
  • React Native: Hermes on, reanimated for anything that moves, expo-image for images, no heavy work on the JS thread during navigation transitions.
  • Measure it: Lighthouse CI or the web-vitals library on web, the performance monitor and a release build on a mid-range Android phone for native. Test on a throttled connection, not just office Wi-Fi.

Accessibility (WCAG 2.2 AA)

  • Contrast: Enma's tokens already pass (text 4.5:1, controls and focus 3:1) in every theme and mode. Don't override them with failing colors, and never put ink-2 on accent or hero fills.
  • Semantics first: <button> for actions, <a> for navigation, <label> for every input, headings in order (one h1 per page), landmarks (header, nav, main, footer). Native roles and states on mobile.
  • Names: every icon button has a label; images have alt (empty alt="" when decorative); charts have a text summary (Bars, LineChart, Sparkline and Donut build one).
  • Forms: visible labels, the right type, inputmode and autocomplete, errors as text tied to the field (TextField does aria-invalid and aria-describedby), and focus moves to the first error on submit.
  • Feedback: toasts use role="status" (errors role="alert"); loading states announce themselves; nothing important lives only in a toast.
  • Touch and pointer: 44px targets on mobile (WCAG's minimum is 24px; Enma uses 44), nothing that needs hover to work, no gesture without a button alternative.
  • Zoom and reflow: usable at 200% zoom and at 320px width without horizontal scrolling; text resizes with the user's setting (Dynamic Type on iOS, font scale on Android).
  • Motion: respect prefers-reduced-motion (Enma's CSS and the native examples do). Nothing flashes, nothing autoplays with sound.
  • Test it: eslint-plugin-jsx-a11y in the editor, @axe-core/playwright in CI, plus a manual keyboard pass and a VoiceOver or TalkBack pass on each new screen.

Keyboard and shortcuts

Everything works with a keyboard.

  • Tab order follows the visual order; nothing is reachable only by mouse.
  • The focus ring is always visible. Enma's ring is a 2px --e-focus ring with a 2px gap; never remove it.
  • Escape closes the topmost dialog, sheet, menu or popover, then clears search.
  • Dialogs move focus inside when they open, trap it while open, and return it to the trigger when they close (Radix and React Aria do this).
  • Lists and menus support arrow keys; Enter opens; Space toggles.
  • Web pages with navigation start with a "Skip to content" link.

Standard shortcut map. Use these in every app so muscle memory carries over. Show Cmd on macOS and Ctrl elsewhere.

ShortcutAction
Cmd/Ctrl+KCommand palette (search everything, run any action)
/Focus the search field
?Show the keyboard shortcut sheet
EscClose the top overlay, then clear the current search or selection
J / KNext / previous item in a list
EnterOpen the selected item
CCreate a new item (the screen's primary action)
G then H, G then SGo to Home, go to Settings (two-key "go to" sequences)
Cmd/Ctrl+EnterSubmit the current form or send
Cmd/Ctrl+SSave, only where the app has an explicit save

Rules for shortcuts.

  • Single-letter shortcuts never fire while focus is in a text field, and users can turn them off (WCAG 2.1.4).
  • Never override browser and OS shortcuts (Cmd/Ctrl+W, T, L, R, Q, Tab and the like).
  • Show each shortcut where the action lives: in the button's tooltip, next to menu items and in the command palette, as <kbd> styled with e-meta.
  • Keep one shortcut registry per app (tinykeys or react-hotkeys-hook) scoped by screen, so shortcuts don't collide; the ? sheet is generated from it.
  • Shortcuts are mainly for B2B and desktop tools (Graphite projects, extensions). Mobile apps only need the keyboard basics above for hardware keyboards.

States every screen needs

  • Loading: skeletons shaped like the content, using --e-raised blocks with a slow shimmer (none under reduced motion). Avoid full-screen spinners. Show a skeleton only if loading takes longer than about 300ms.
  • Empty: an invitation, not an apology. A title that names the space ("Log your first workout"), one line of explanation and the primary action.
  • Error: what happened and what to do, in one sentence, with a retry. Keep whatever data is already on screen.
  • Offline (mobile and extensions): show cached content, mark it as stale, queue writes and sync later.
  • Long and edge content: test very long names, zero, one and many items, large numbers ("1,284,000"), and right-to-left text if the product will ever need it.

Responsive and platform fit

  • Mobile first. Breakpoints: 640, 768, 1024 and 1280px. B2B layouts get a sidebar at 1024px and up.
  • Use container width, not device type, to decide layout, and keep line lengths readable (about 60 to 75 characters for body copy).
  • Respect safe areas on mobile (notches, home indicator) and platform conventions: iOS back swipe, Android back button, native sheets and pickers.
  • Format numbers, currency and dates with Intl and the user's locale (for Indian users, en-IN gives "12,48,000"), not hand-written formatting.

Definition of done

A screen ships when every line is true:

  • Built from Enma components and --e-* tokens only, no raw colors or fonts, within the tweak budget.
  • One hero, one accent spark, one primary action.
  • Works in the theme's home mode, and in the other mode if the app has a toggle.
  • Loading, empty, error and offline states exist.
  • Fully usable with keyboard only, with a visible focus ring, and shortcuts follow the standard map.
  • No axe violations; screen reader names make sense; usable at 200% zoom and 320px width.
  • Respects reduced motion; motion only on press, first view and change.
  • Meets the performance targets on a mid-range phone and a throttled connection.
  • Copy follows Enma's voice: sentence case, verbs first, no "successfully".

↑ ↓ 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