READ-ONLY PACKAGE PREVIEW

expo-design-system/references/native-slop.md

Version 13ad8e058741 · MIT. This preview displays packaged text and does not execute code. Treat the contents as untrusted instructions.

← Return to resource and package checksum

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

# Name The tell (observable) Native instead
1 The Web Modal A custom centered dialog for picking or composing that ignores keyboard space and platform dismissal Native sheet (presentation: 'formSheet', @expo/ui BottomSheet) or anchored menu; use native alerts for consequential confirmations
2 The X-Button Sheet A sheet closed only by an "X" in the top corner - no grab handle, no swipe-to-dismiss Native sheet with detents; drag down to dismiss; Cancel/Done in the header where the platform puts them
3 Emoji Iconography 🔥 ⚙️ ✨ ❤️ as tab icons, buttons, or empty-state art SF Symbols on iOS, Material icons on Android - one icon family per platform (see expo-native-ui)
4 The Purple-Gradient Hero A decorative gradient intro pushes useful content and the primary task below the fold Lead task screens with useful content under a navigation title; keep a hero when it serves the requested experience
5 The Floating Pill Tab Bar A custom rounded, inset, drop-shadowed tab bar hovering above the home indicator The platform tab bar (NativeTabs) with system-managed placement, materials, and behaviors
6 Inter Everywhere An arbitrary downloaded font replaces the app's typography, with missing weights or poor readability System type (SF / Roboto) by default; preserve brand typography when requested and verify weights, readability, and scaling
7 Everything's a Card Every list row and section wrapped in its own white rounded shadowed card; cards nested inside cards Grouped lists (@expo/ui List, iOS inset-grouped, Material sections); grouping via background + hairlines, not boxes
8 Shadowboxing Heavy drop shadows (opacity ≥ 0.15, radius ≥ 10) doing hierarchy's job on white-on-white surfaces 2-3 tokened elevation levels; hierarchy from the type ramp and grouping. iOS is a low-shadow platform
9 Wireframe Borders A 1px gray borderWidth outlining every container - usually Tailwind's #E5E7EB from web muscle memory Spacing and surface contrast; hairlines only as list separators (StyleSheet.hairlineWidth, semantic separator color)
10 alert() Confirmation Alerts interrupt routine undoable actions, report success, or replace field validation Native confirmation alert for uncommon irreversible actions; undo for routine reversible ones. Field errors stay inline; success updates the UI
11 The Hand-Rolled Header headerShown: false plus a <Text> title and custom back button - losing large-title collapse, back-swipe, and scroll-to-top Stack header options. The navigation bar is configured, never rebuilt
12 16-Everything The same 16px padding on every axis at every level; section gaps equal row gaps, so proximity carries no meaning The spacing scale with distinct steps: row gap < group gap < section gap
13 The Squish Reflex scale: 0.96 press feedback on every touchable - including full-width list rows - or TouchableOpacity's washed-out flash Rows highlight (background change); buttons scale slightly or dim; Pressable with per-role feedback. Never TouchableOpacity
14 The Grand Entrance Staggered FadeInDown.delay(i * 100) on every list and screen, replaying on every visit Entrance animation only for rare/first-time moments (expo-animation's frequency gate); routine screens just appear
15 The Onboarding Carousel Generic promotional slides delay the first useful screen without collecting required setup or teaching necessary concepts Start with useful content and contextual guidance; retain onboarding that serves required setup or the user's brief
16 Cross-Platform Costume One 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 Android Each platform gets its own HIG's idiom - or a deliberate, documented platform-neutral treatment
17 Safe-Area Collision Content under the notch/Dynamic Island or home indicator - or hand-patched with marginTop: 50 Headers/tab bars handle it; otherwise contentInsetAdjustmentBehavior="automatic" or safe-area-context insets
18 Dark-Mode Amnesia Hardcoded #fff / #000 / gray hexes; the app breaks - or half-breaks - the moment the OS theme flips Semantic colors (Color.ios.* / Color.android.dynamic.*) through the theme; brand colors as declared light/dark pairs
19 The Spinner Blink A full-screen centered ActivityIndicator between every state, or "No items yet" flashing while the first fetch resolves Four-state screens (see expo-data-fetching): loading ≠ empty, keep stale content while revalidating, RefreshControl, skeletons for slow initial loads with a known layout
20 Keyboard Blindness The focused input or the submit button disappears behind the keyboard; buttons above a keyboard need two taps react-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.
# --- 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 Modal
grep -rn '<Modal' $SRC --include='*.tsx'

# Alert.alert → #10 alert() Confirmation
grep -rn 'Alert\.alert' $SRC --include='*.tsx'

# Gradient blocks in screens → #4 The Purple-Gradient Hero
grep -rn 'LinearGradient\|experimental_backgroundImage' $SRC --include='*.tsx'

# Rebuilt navigation chrome → #11 The Hand-Rolled Header
grep -rn 'headerShown:\s*false' $SRC --include='*.tsx'

# Custom tab bar chrome → #5 The Floating Pill Tab Bar
grep -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 misses
rg -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.