Patterns
How screens are put together in each kit, and what to avoid. Generated from the kits' DESIGN_SYSTEM.md.
These are the same rules the agent reads, straight from each kit's DESIGN_SYSTEM.md.
Mobile
Patterns
- Screen skeleton:
ScrollView className="bg-background flex-1" contentContainerClassName="gap-5 p-5 pb-32"→ sections (SectionHeader+CardofListRows) →StickyBottomBarafter the ScrollView when there is a primary action. - Multi-step flow: one route,
useState<Step>inside, one header, oneStepper, oneStickyBottomBar. Not one route per step. - Tracking: what already happened and what comes next (an order, a delivery, an application) is a
Timelinein aCard.Stepperis for a flow the person is filling in. - Asking for a rating: after the thing is done (an order delivered), as an input
Ratingin its ownCardwith a toast to thank them. Never in the middle of a task. Show a score as a displayRatingwith the number. - Pickers:
OptionSheeton phones;Selectwhen the list is short and the field sits in a form. - Confirmations:
AlertDialogfor reversible,SwipeToConfirmfor money or deletion. - Success:
SuccessScreen+StickyBottomBarwith "Done". Always. - Loading:
Skeletonfor content shapes,Spinnerinside buttons (tone="primary-foreground"on a filled one),Progresswhen determinate. - Motion: anything that slides, springs or moves calls
useMotion()/useReducedMotion()fromlib/reduced-motion.tsand collapses to 0ms when the OS asks.components/uigets this from reanimated'sReduceMotion.System; the kit'sAnimatedcode has no equivalent, so it is not optional — a new animated component without it is a bug. - Shadow: only on something you can press, or something floating above the page (dialogs, sheets, menus, toasts, the FloatingButton). Content is flat — that includes inputs, which are neither.
- Permission:
PermissionPrimerbefore the OS dialog, always with a skip that runs the simulated path. Never show a raw denied state. Keep its copy in step with the strings inapp.json. - Imagery: the kit ships no raster art.
Placeholder(seeded, themed) fills image slots;Spotis the illustration for empty, success and permission screens.
Anti-patterns
- ✗ Cards inside cards. ✗ Section titles inside the card. ✗ Everything centred.
- ✗ Radio and checkbox choices in one group — split them; one picks one, the other picks any.
- ✗ Identical card grids (same icon + heading + body repeated).
- ✗ Same padding on every element; vary it to create rhythm.
- ✗ Modals as the default home for secondary content.
- ✗ Brand colour on selected chips/tabs. ✗ Grey-on-grey text below 4.5:1 contrast.
- ✗ Tap targets under 44×44. ✗ Icon-only buttons without
accessibilityLabel. - ✗ A control without a name: a Switch, RadioGroupItem or Checkbox needs a
Label htmlForitsid, or anaria-label(a Switch at the end of a ListRow). ✗accessibilityState/accessibilityValuein new components: the web export drops them; use thearia-*props (aria-checked,aria-selected,aria-valuenow), which native reads too. A selectedbutton(chip, segment, day) keepsaccessibilityState={{ selected }}for native and addsaria-pressedfor web.
Web
Patterns
- App page:
AppShellin the prototype'slayout.tsx→PageHeader→ 2–4StatTiles →Cards or aDataTable. One primary action per page, in the PageHeader. - Marketing page:
Hero→FeatureGrid→ social proof or a product shot →PricingCards → FAQ (Accordion) → a closing call to action. One promise, one primary action, repeated at the end. - AI conversation:
ChatMessages in a centred column (max-w-3xl),ChatComposerpinned at the bottom. Show work as it happens (ThinkingIndicator,ToolCallCard), stream the answer (StreamingText), and ask with anApprovalCardbefore anything irreversible or costly (consent before consequence). Past conversations go in aChatThreadList: a sidebar on desktop, a Sheet on small screens. When the assistant can use files, giveChatComposeranaccept; sent files show asAttachmentChips in the user's turn. An answer built on the person's data or documents cites them (CitedText+SourceList); the latest answer can end withFollowUpSuggestions. A cancelled tool call isstopped, noterror. - Forms: a
Labelfor every field,DatePickerfor a single date, errors next to the field (aria-invalid+ atext-destructiveline), the submit button names the action. - Confirmations:
AlertDialogfor destructive actions, its button says what happens.toast()for done-and-undo. - Empty and loading: every list has an
EmptyStatewith the next step;Skeletonfor content shapes. - Shadow: only on what you can press or what floats (dialogs, popovers, menus, toasts). Content is flat.
- Responsive: design at 375px and 1280px. Sidebars collapse into a sheet (
AppShelldoes), tables scroll inside their card, grids drop columns.
Worked examples of the first three: /dashboard (an AppShell app with a chart, a filtered table, a dialog
form, settings and a guarded delete), /landing and /assistant.
Anti-patterns
- ✗ Cards inside cards. ✗ Identical icon + heading + body cards repeated as filler.
- ✗ Brand colour on selected tabs, chips or nav items. ✗ Grey-on-grey text below 4.5:1.
- ✗ More than one primary button in view. ✗ “OK”/“Submit” as the label of a consequential action.
- ✗ Modals as the default home for secondary content. ✗ Icon-only buttons without
aria-label. - ✗ An assistant that acts without asking, or hides what it did.
The hallucination guard
Before writing JSX, list the components you intend to use. Every name must appear in the registry
above exactly. If you need something else: stop, describe the gap in one line, and use the
add-component skill. Do not import from react-native-paper, @expo/vector-icons, gluestack
or any UI library that is not in package.json.