---
name: enma-frontend
description: Set up and build frontends with Enma, Manish Mandal's design system, on any platform (Next.js, Vite, React Native and Expo, Chrome extensions, VS Code webviews, plain HTML and Claude artifacts, CLIs). Use when starting a project with Enma, wiring Enma into an existing app, building a screen end to end, or checking a screen against Enma's definition of done. Pair it with the enma-design skill for the visual rules.
---

# Enma frontend

The companion to `enma-design`: how to set Enma up, build screens in the right order and ship them to Enma's standard.

## 1. Set up the project

Write the UI decision at the top of the project's README or AGENTS.md first: `UI: Enma · <theme> · <mode> (home), toggle: no`.

| Platform                         | Setup                                                                                                                                                                               |
| -------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Next.js, Vite, any React web app | Install `enma-design`, `import 'enma-design/css'` and `import 'enma-design/fonts/<theme>'` once, wrap the app in `<EnmaRoot theme>` or set `data-enma` and `data-theme` on `<html>` |
| React Native, Expo               | Install `enma-design` plus `react-native-reanimated` and `expo-haptics`, load the theme's `@expo-google-fonts/*`, wrap the app in `<EnmaProvider theme>` from `enma-design/native`  |
| Chrome extension                 | `@enma-design/css` with local fonts; UI injected into pages goes inside a Shadow DOM root                                                                                           |
| VS Code webview                  | `@enma-design/css` plus `@enma-design/css/vscode.css`, `data-enma="graphite"` and `data-theme` from VS Code's body class                                                            |
| Plain HTML, Claude artifacts     | Inline `enma.css`, set the root attributes, use the class recipes                                                                                                                   |
| CLI                              | No CSS: apply the rules (one accent, units, words with status, `NO_COLOR`)                                                                                                          |

Exact code for each: [references/setup.md](references/setup.md). Starters with everything wired: `pnpm dlx tiged --mode=git manishMandal02/enma-design/starters/<react-vite|next|expo|chrome-extension|html> my-app` (`--mode=git` clones over SSH, which the private repo needs).

Install from npm with `pnpm add enma-design` (no token or registry setup); imports read `enma-design/react`, `enma-design/css` and so on.

## 2. Build each screen in this order

1. Layout and navigation (`TabBar` on mobile, a sidebar or top bar on web).
2. The hero (`Card variant="hero"` with a `Stat`, or a display title).
3. Content from existing components (`ListGroup`, `Table`, `Card`, `Stat`, `Bars`, `LineChart`).
4. States: loading, empty, error and offline.
5. Only then custom UI, styled with `--e-*` roles or the Tailwind mapping (`enma-design/tailwind.css`), never raw values.

`className` and `style` on components are for layout only (margin, grid placement, width). Never restyle a component's colors, radius or type from outside; change the system instead.

## 3. States every screen needs

- **Loading:** skeletons shaped like the content (`--e-raised` blocks, slow shimmer, none under reduced motion), only after about 300ms. No full-screen spinners.
- **Empty:** an invitation: a title that names the space ("Log your first workout"), one line and the primary action.
- **Error:** what happened and what to do, in one sentence, with a retry. Keep the data already on screen.
- **Offline (mobile, extensions):** cached content marked as stale; queue writes.
- **Edges:** very long names; zero, one and many items; large numbers ("1,284,000").

## 4. Accessibility (WCAG 2.2 AA)

- Semantics first: `<button>` for actions, `<a>` for navigation, `<label>` for every input, one `h1`, landmarks.
- Every icon button has a label, images have `alt`, charts have a text summary (Enma's charts build one).
- Forms: visible labels, the right `type`, `inputmode` and `autocomplete`; errors tied to the field; focus moves to the first error on submit.
- Toasts use `role="status"` (errors `role="alert"`); nothing important lives only in a toast.
- 44px touch targets on mobile, nothing hover-only, usable at 200% zoom and 320px width.
- Respect `prefers-reduced-motion`. Never remove the focus ring.
- Test: `eslint-plugin-jsx-a11y`, axe (`@axe-core/playwright` or `jest-axe`), a keyboard pass and a screen reader pass.

## 5. Keyboard and shortcuts

Everything works with a keyboard, in visual order, with a visible focus ring. Escape closes the top overlay. Dialogs trap focus and return it to the trigger. Standard map: Cmd/Ctrl+K palette, `/` search, `?` shortcut sheet, `J`/`K` next and previous, `Enter` open, `C` create, `G` then a letter to go somewhere, Cmd/Ctrl+Enter submit. Single-letter shortcuts never fire in text fields and can be turned off. Details: [references/standards.md](references/standards.md).

## 6. Performance budgets

LCP under 2.5s, INP under 200ms, CLS under 0.1 (75th percentile). App shell under about 150 KB of JavaScript gzipped. Only the active theme's fonts, `woff2`, `font-display: swap`. Animate only `transform` and `opacity`. Virtualize lists over about 100 rows.

## 7. Definition of done

A screen ships when every line is true:

- [ ] Built from Enma components and `--e-*` tokens only, 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; 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".
