Deft
Ask AI

Search

Search skills, authors and topics

expo / skills

expo-design-system

Build and maintain a design system inside an Expo app: design tokens, component variant conventions, extending NativeWind, Tamagui, Restyle or Unistyles, fixing apps that look AI-generated, and auditing for design-system drift.

Install

npx skills add https://github.com/expo/skills --skill expo-design-system

Native Slop: Named Anti-Pattern Tells

Recurring mistakes in generated React Native apps, with names, observable tells, and preferred replacements. Use these as review prompts: explain what harms the task, readability, or platform behavior. A card, font, gradient, or onboarding flow is not a defect by itself; respect the user's brief and existing design system. Interaction failures such as obscured inputs or false-empty states still need fixing.

The 20 tells

#NameThe tell (observable)Native instead
1The Web ModalA custom centered dialog for picking or composing that ignores keyboard space and platform dismissalNative sheet (presentation: 'formSheet', @expo/ui BottomSheet) or anchored menu; use native alerts for consequential confirmations
2The X-Button SheetA sheet closed only by an "X" in the top corner - no grab handle, no swipe-to-dismissNative sheet with detents; drag down to dismiss; Cancel/Done in the header where the platform puts them
3Emoji Iconography🔥 ⚙️ ✨ ❤️ as tab icons, buttons, or empty-state artSF Symbols on iOS, Material icons on Android - one icon family per platform (see expo-native-ui)
4The Purple-Gradient HeroA decorative gradient intro pushes useful content and the primary task below the foldLead task screens with useful content under a navigation title; keep a hero when it serves the requested experience
5The Floating Pill Tab BarA custom rounded, inset, drop-shadowed tab bar hovering above the home indicatorThe platform tab bar (NativeTabs) with system-managed placement, materials, and behaviors
6Inter EverywhereAn arbitrary downloaded font replaces the app's typography, with missing weights or poor readabilitySystem type (SF / Roboto) by default; preserve brand typography when requested and verify weights, readability, and scaling
7Everything's a CardEvery list row and section wrapped in its own white rounded shadowed card; cards nested inside cardsGrouped lists (@expo/ui List, iOS inset-grouped, Material sections); grouping via background + hairlines, not boxes
8ShadowboxingHeavy drop shadows (opacity ≥ 0.15, radius ≥ 10) doing hierarchy's job on white-on-white surfaces2-3 tokened elevation levels; hierarchy from the type ramp and grouping. iOS is a low-shadow platform
9Wireframe BordersA 1px gray borderWidth outlining every container - usually Tailwind's #E5E7EB from web muscle memorySpacing and surface contrast; hairlines only as list separators (StyleSheet.hairlineWidth, semantic separator color)
10alert() ConfirmationAlerts interrupt routine undoable actions, report success, or replace field validationNative confirmation alert for uncommon irreversible actions; undo for routine reversible ones. Field errors stay inline; success updates the UI
11The Hand-Rolled HeaderheaderShown: false plus a <Text> title and custom back button - losing large-title collapse, back-swipe, and scroll-to-topStack header options. The navigation bar is configured, never rebuilt
1216-EverythingThe same 16px padding on every axis at every level; section gaps equal row gaps, so proximity carries no meaningThe spacing scale with distinct steps: row gap < group gap < section gap
13The Squish Reflexscale: 0.96 press feedback on every touchable - including full-width list rows - or TouchableOpacity's washed-out flashRows highlight (background change); buttons scale slightly or dim; Pressable with per-role feedback. Never TouchableOpacity
14The Grand EntranceStaggered FadeInDown.delay(i * 100) on every list and screen, replaying on every visitEntrance animation only for rare/first-time moments (expo-animation's frequency gate); routine screens just appear
15The Onboarding CarouselGeneric promotional slides delay the first useful screen without collecting required setup or teaching necessary conceptsStart with useful content and contextual guidance; retain onboarding that serves required setup or the user's brief
16Cross-Platform CostumeOne platform wearing the other's uniform: a FAB or ripple in an iOS-idiom app; iOS back-chevrons, large titles, or iOS-styled switches on AndroidEach platform gets its own HIG's idiom - or a deliberate, documented platform-neutral treatment
17Safe-Area CollisionContent under the notch/Dynamic Island or home indicator - or hand-patched with marginTop: 50Headers/tab bars handle it; otherwise contentInsetAdjustmentBehavior="automatic" or safe-area-context insets
18Dark-Mode AmnesiaHardcoded #fff / #000 / gray hexes; the app breaks - or half-breaks - the moment the OS theme flipsSemantic colors (Color.ios.* / Color.android.dynamic.*) through the theme; brand colors as declared light/dark pairs
19The Spinner BlinkA full-screen centered ActivityIndicator between every state, or "No items yet" flashing while the first fetch resolvesFour-state screens (see expo-data-fetching): loading ≠ empty, keep stale content while revalidating, RefreshControl, skeletons for slow initial loads with a known layout
20Keyboard BlindnessThe focused input or the submit button disappears behind the keyboard; buttons above a keyboard need two tapsreact-native-keyboard-controller tracks the real keyboard frame (expo-animation keyboard recipe); keyboardShouldPersistTaps="handled" for forms/search, "always" when unhandled taps must also keep the keyboard open

For confirmation choices, follow Apple’s alert guidance: uncommon irreversible actions warrant confirmation; routine undoable actions generally do not.

Grep the greppable tells

Same shell-variable convention as audit.md (set $SRC and $THEME first, run from the repo root). These searches find candidates, not verified defects. Two hit classes:

  • review-each - legitimate uses exist; check each hit against the tell's description.
  • advisory - hits only suggest the tell; confirm on a screenshot.
bash
# --- review-each ---# Touchable* anywhere → #13 The Squish Reflex (Pressable only)grep -rn 'TouchableOpacity\|TouchableHighlight\|TouchableWithoutFeedback' $SRC --include='*.tsx'
# fontFamily outside the theme → #6 Inter Everywhere (may reference a valid brand token)grep -rn 'fontFamily:' $SRC --include='*.tsx' | grep -v "^$THEME/"
# RN <Modal> for picking/composing → #1 The Web Modalgrep -rn '<Modal' $SRC --include='*.tsx'
# Alert.alert → #10 alert() Confirmationgrep -rn 'Alert\.alert' $SRC --include='*.tsx'
# Gradient blocks in screens → #4 The Purple-Gradient Herogrep -rn 'LinearGradient\|experimental_backgroundImage' $SRC --include='*.tsx'
# Rebuilt navigation chrome → #11 The Hand-Rolled Headergrep -rn 'headerShown:\s*false' $SRC --include='*.tsx'
# Custom tab bar chrome → #5 The Floating Pill Tab Bargrep -rn 'tabBarStyle' $SRC --include='*.tsx'
# --- advisory ---# Emoji as UI glyphs → #3 Emoji Iconography (content strings may contain emoji; glyph-as-icon is the tell)# \x{FE0F} catches text-default emoji rendered emoji-style (⚙️ ❤️), which Emoji_Presentation alone missesrg -n '[\p{Emoji_Presentation}\x{FE0F}]' $SRC -g '*.tsx'

audit.md §1 finds related token candidates for #18 Dark-Mode Amnesia, #12 16-Everything, and #8 Shadowboxing. Token compliance does not prove readable dark mode, useful spacing hierarchy, or restrained shadows; inspect the rendered screen too.

Screenshot-only tells (no grep precise enough to trust): #2 X-Button Sheet, #7 Everything's a Card, #9 Wireframe Borders, #15 Onboarding Carousel, #16 Cross-Platform Costume, #17 Safe-Area Collision. Three more need a running app: #14 The Grand Entrance (re-enter a screen), #19 The Spinner Blink (watch the first load and a refetch), #20 Keyboard Blindness (keyboard open). Check them per SKILL.md's Self-Critique Pass, #16 on both platforms.

Growing the list

A new tell earns its place only after the same failure appears repeatedly across generations - one model's one-off quirk stays out until it repeats. Keep the list near 20 entries: recognition degrades with length.