agy-superpowers 5.1.1 → 5.1.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (54) hide show
  1. package/README.md +22 -2
  2. package/package.json +1 -1
  3. package/template/agent/.shared/mobile-uiux-promax/data/accessibility.csv +25 -0
  4. package/template/agent/.shared/mobile-uiux-promax/data/animation.csv +22 -0
  5. package/template/agent/.shared/mobile-uiux-promax/data/components.csv +21 -0
  6. package/template/agent/.shared/mobile-uiux-promax/data/gestures.csv +26 -0
  7. package/template/agent/.shared/mobile-uiux-promax/data/layout.csv +21 -0
  8. package/template/agent/.shared/mobile-uiux-promax/data/navigation.csv +27 -0
  9. package/template/agent/.shared/mobile-uiux-promax/data/onboarding.csv +17 -0
  10. package/template/agent/.shared/mobile-uiux-promax/data/platform.csv +22 -0
  11. package/template/agent/.shared/mobile-uiux-promax/data/stacks/flutter.csv +19 -0
  12. package/template/agent/.shared/mobile-uiux-promax/data/stacks/jetpack-compose.csv +18 -0
  13. package/template/agent/.shared/mobile-uiux-promax/data/stacks/react-native.csv +20 -0
  14. package/template/agent/.shared/mobile-uiux-promax/data/stacks/swiftui.csv +18 -0
  15. package/template/agent/.shared/mobile-uiux-promax/data/ux-laws.csv +16 -0
  16. package/template/agent/.shared/mobile-uiux-promax/scripts/mobile-search.py +157 -0
  17. package/template/agent/.shared/ui-ux-pro-max/data/charts.csv +26 -0
  18. package/template/agent/.shared/ui-ux-pro-max/data/colors.csv +97 -0
  19. package/template/agent/.shared/ui-ux-pro-max/data/landing.csv +31 -0
  20. package/template/agent/.shared/ui-ux-pro-max/data/products.csv +97 -0
  21. package/template/agent/.shared/ui-ux-pro-max/data/prompts.csv +24 -0
  22. package/template/agent/.shared/ui-ux-pro-max/data/stacks/flutter.csv +53 -0
  23. package/template/agent/.shared/ui-ux-pro-max/data/stacks/html-tailwind.csv +56 -0
  24. package/template/agent/.shared/ui-ux-pro-max/data/stacks/nextjs.csv +53 -0
  25. package/template/agent/.shared/ui-ux-pro-max/data/stacks/react-native.csv +52 -0
  26. package/template/agent/.shared/ui-ux-pro-max/data/stacks/react.csv +54 -0
  27. package/template/agent/.shared/ui-ux-pro-max/data/stacks/svelte.csv +54 -0
  28. package/template/agent/.shared/ui-ux-pro-max/data/stacks/swiftui.csv +51 -0
  29. package/template/agent/.shared/ui-ux-pro-max/data/stacks/vue.csv +50 -0
  30. package/template/agent/.shared/ui-ux-pro-max/data/styles.csv +59 -0
  31. package/template/agent/.shared/ui-ux-pro-max/data/typography.csv +58 -0
  32. package/template/agent/.shared/ui-ux-pro-max/data/ux-guidelines.csv +100 -0
  33. package/template/agent/.shared/ui-ux-pro-max/scripts/__pycache__/core.cpython-313.pyc +0 -0
  34. package/template/agent/.shared/ui-ux-pro-max/scripts/core.py +236 -0
  35. package/template/agent/.shared/ui-ux-pro-max/scripts/search.py +61 -0
  36. package/template/agent/.tests/TESTS.md +119 -0
  37. package/template/agent/.tests/mobile-uiux-promax/test_search.py +266 -0
  38. package/template/agent/.tests/run_tests.py +86 -0
  39. package/template/agent/patches/skills-patches.md +20 -0
  40. package/template/agent/skills/brainstorming/SKILL.md +57 -0
  41. package/template/agent/skills/frontend-design/SKILL.md +147 -0
  42. package/template/agent/skills/frontend-design/reference/color-and-contrast.md +117 -0
  43. package/template/agent/skills/frontend-design/reference/interaction-design.md +159 -0
  44. package/template/agent/skills/frontend-design/reference/motion-design.md +150 -0
  45. package/template/agent/skills/frontend-design/reference/responsive-design.md +161 -0
  46. package/template/agent/skills/frontend-design/reference/spatial-design.md +122 -0
  47. package/template/agent/skills/frontend-design/reference/typography.md +124 -0
  48. package/template/agent/skills/frontend-design/reference/ux-writing.md +127 -0
  49. package/template/agent/skills/mobile-uiux-promax/SKILL.md +139 -0
  50. package/template/agent/skills/subagent-driven-development/implementer-prompt.md +4 -1
  51. package/template/agent/skills/verification-before-completion/SKILL.md +11 -0
  52. package/template/agent/skills/writing-plans/SKILL.md +4 -1
  53. package/template/agent/workflows/mobile-uiux-promax.md +137 -0
  54. package/template/agent/workflows/ui-ux-pro-max.md +231 -0
package/README.md CHANGED
@@ -451,8 +451,28 @@ This setup enforces four core principles across every task:
451
451
 
452
452
  ## Credits
453
453
 
454
- - **[Superpowers](https://github.com/obra/superpowers)** by [Jesse Vincent](https://blog.fsck.com) & [Prime Radiant](https://primeradiant.com) the upstream skills library this repo is built on.
455
- - Antigravity integration & workflow adaptation by [@bonnguyenitc](https://github.com/bonnguyenitc).
454
+ This project stands on the shoulders of many great open-source projects. A huge thank you to all of them! 🙏
455
+
456
+ ### 🏗️ Skill Sources
457
+
458
+ Content from these repos was ported, adapted, and integrated into the skills library:
459
+
460
+ | Repository | Author | Skills |
461
+ |---|---|---|
462
+ | [obra/superpowers](https://github.com/obra/superpowers) | [Jesse Vincent](https://blog.fsck.com) & [Prime Radiant](https://primeradiant.com) | **Core foundation** — upstream skills library this repo is built on |
463
+ | [vercel-labs/agent-skills](https://github.com/vercel-labs/agent-skills) | Vercel Labs | 66 React/Next.js rules + 36 React Native rules (in `frontend-developer` + `mobile-developer`) |
464
+ | [antfu/skills](https://github.com/antfu/skills) | [Anthony Fu](https://github.com/antfu) | 44 Vue/Nuxt rules (in `frontend-developer`) |
465
+ | [vuejs-ai/skills](https://github.com/vuejs-ai/skills) | vuejs-ai | Vue ecosystem agent skill rules (upstream of antfu/skills) |
466
+ | [kevmoo/dash_skills](https://github.com/kevmoo/dash_skills) | [Kevin Moore](https://github.com/kevmoo) | 8 Dart & Flutter best-practice rules (in `mobile-developer`) |
467
+ | [new-silvermoon/awesome-android-agent-skills](https://github.com/new-silvermoon/awesome-android-agent-skills) | new-silvermoon | 17 Android/Compose/Kotlin rules (in `mobile-developer`) |
468
+ | [AvdLee/SwiftUI-Agent-Skill](https://github.com/AvdLee/SwiftUI-Agent-Skill) | [Antoine van der Lee](https://github.com/AvdLee) | 19 SwiftUI reference files (in `mobile-developer`) |
469
+ | [msitarzewski/agency-agents](https://github.com/msitarzewski/agency-agents) | msitarzewski | Deliverable-focused, workflow-oriented agent patterns (inspired indie hacker skills) |
470
+ | [nextlevelbuilder/ui-ux-pro-max-skill](https://github.com/nextlevelbuilder/ui-ux-pro-max-skill) | nextlevelbuilder | UI/UX Pro Max search databases — curated style, typography, color, UX, and stack knowledge (in `.shared/ui-ux-pro-max`) |
471
+
472
+ ---
473
+
474
+
475
+ Antigravity integration, workflow adaptation & expansion skills (12 indie hacker skills, UI/UX intelligence databases, mobile design system) by [@bonnguyenitc](https://github.com/bonnguyenitc).
456
476
 
457
477
  ---
458
478
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "agy-superpowers",
3
- "version": "5.1.1",
3
+ "version": "5.1.3",
4
4
  "description": "Superpowers skills library for Google Antigravity agent — scaffold .agent/ with one command",
5
5
  "type": "module",
6
6
  "bin": {
@@ -0,0 +1,25 @@
1
+ Category,Issue,Platform,iOS Tool,Android Tool,Minimum Spec,Do,Don't,Code Example,WCAG Level
2
+ Touch Target Size,interactive element too small to tap accurately,Both,Accessibility Inspector: tap target size audit; UIAccessibility.focusedElement,AccessibilityScanner app; Compose accessibilityTest; atLeast() matcher,iOS: 44×44pt minimum; Android: 48×48dp recommended (Google) 56×56dp for high-frequency,Add transparent padding to extend tap area beyond visual bounds; use frame/padding modifiers,Make icon buttons 20×20 without padding; rely on tiny text links as only action,"iOS: .frame(minWidth:44,minHeight:44); Android: Modifier.minimumTouchTargetSize(48.dp)",AA
3
+ Screen Reader Labels,element without accessible name label,Both,VoiceOver (iPhone) — swipe to navigate; enabled in Settings > Accessibility > VoiceOver,TalkBack (Android) — enabled in Settings > Accessibility > TalkBack,Every interactive element must have a name; images must have text alternative,"Add accessibilityLabel per element; describe function not appearance; images: brief description; decorative images: hidden","Icon buttons with no accessibilityLabel; labels that say 'Button' without context; duplicate labels for different elements","iOS: .accessibilityLabel('Add to cart'); Android: contentDescription=""Add to cart""",A
4
+ Heading Hierarchy,missing headings poor heading structure,Both,VoiceOver Rotor: Headings; navigate by heading,"TalkBack heading navigation; AccessibilityNodeInfo.getExtras() heading check","H1 per screen; logical hierarchy H1 > H2 > H3; no skipped levels (H1 → H3)","Mark screen title as H1; section headers as H2; avoid decorating text as heading for visual style only","Multiple H1s per screen; visual headings with no heading role; marking everything as heading for VoiceOver scrolling","iOS: .accessibilityAddTraits(.header); Android: ViewCompat.setAccessibilityHeading(view, true)",A
5
+ Focus Order,focus order unexpected illogical tab order,Both,VoiceOver swiping order revealed in testing,TalkBack swiping order revealed; AccessibilityNodeInfoDumper,Focus must follow visual reading order (LTR: left→right top→bottom),"Test by swiping through entire screen with VoiceOver/TalkBack; fix with accessibilitySortPriority; use semantic grouping","Focusable elements in DOM/view order that doesn't match visual layout; modal with focusable elements behind it reachable","iOS: .accessibilitySortPriority(); Android: ViewCompat.setAccessibilityPaneTitle(); importantForAccessibility",A
6
+ Dynamic Type Support,dynamic type font scaling text size user preference,iOS,VoiceOver with large text enabled (Settings > Accessibility > Larger Text); Simulator Accessibility > Font Scaling,TalkBack with Font Size increased; adb shell settings put system font_scale 1.3,iOS: must support Extra Small to Accessibility XXXLarge (up to 310% scale); Android: sp units scale automatically,"Use Dynamic Type text styles (title body caption); test at 200%+ scale; layouts must reflow not overflow","Hardcode font sizes in pt/px; clamp text to max 1 line at all sizes; define static width containers that can't expand","iOS: Font.custom('Brand',size:17,relativeTo:.body); Android: textSize in sp units only",AA
7
+ Color Contrast — Text,text contrast low insufficient foreground background,Both,Xcode Accessibility Inspector contrast checker; WWDC color audit tool,"Material Color Utilities contrast checker; Compose Modifier.semantics; Color Contrast Analyzer desktop tool","Normal text: 4.5:1 minimum; Large text (18pt+ or 14pt bold+): 3:1 minimum; UI components: 3:1","Test foreground text against all backgrounds including images; check in dark mode too; use contrast checker during design","Light gray on white; primary brand color text on white if insufficiently dark; placeholder gray as body text color",Xcode Accessibility Inspector: View Hierarchy > Accessibility > contrast ratio value,AA
8
+ Color as Sole Indicator,color only information no other indicator,Both,Accessibility Inspector: display color blind simulation,AccessibilityScanner checks; phone has color blind simulation mode,Do not use color as the only way to convey information — add icon shape pattern or text,"Add icons or text alongside color coding (success=green+checkmark; error=red+X); use pattern in charts","Pure green/red traffic-light status with no other indicator; chart series differentiated only by color line only","iOS: use SF Symbols .checkmark and .xmark alongside color; Android: use Warning / Check Material Icons with color",A
9
+ Announcement for State Changes,state change not announced dynamic content update,Both,VoiceOver: listen for automatic announcements; post UIAccessibility.post(notification:),TalkBack: announceForAccessibility() or AccessibilityEvent.TYPE_ANNOUNCEMENT; Compose semantics liveRegion,All dynamic content changes must be communicated to assistive technology,"Post announcements for: async data loads errors form submission results search results count; use live regions","Silently swapping UI without announcement; posting announcements too frequently (notification storm)","iOS: UIAccessibility.post(notification:.announcement, argument:'3 results found'); Android: ViewCompat.setAccessibilityLiveRegion(view, ViewCompat.ACCESSIBILITY_LIVE_REGION_POLITE)",AA
10
+ Custom Actions (Complex Gestures),swipe gesture custom action accessibility,Both,VoiceOver custom actions: swipe up through Actions rotor item,TalkBack: ViewCompat.addAccessibilityAction(); semantics block actions,"Every gesture-only interaction needs an accessible alternative in 'Actions' menu","Define UIAccessibilityCustomAction for every swipe/long-press/drag interaction; name actions clearly","Swipe-to-delete without Actions alternative; double-tap-hold gesture without custom action; drag reorder without up/down buttons","iOS: accessibilityCustomActions=[UIAccessibilityCustomAction(name:'Delete',target:...)]; Compose: semantics { customActions = [...] }",AA
11
+ Group Elements Semantically,element grouping accessibility focus clutter,Both,VoiceOver: each leaf being individually focused clutters navigation,TalkBack: too many focus stops per list row; screenReaderFocusable attribute,Group visually related elements into single accessible element where content is inseparable,"Use shouldGroupAccessibilityChildren / accessibilityElement(children:.combine) to group icon+label+value into one focus stop","Individually accessible label AND value AND button in same row when they're semantically one unit; user swipes 10× for simple info","iOS: .accessibilityElement(children: .combine); .accessibilityLabel('Netflix, 4.5 stars, 2 hours'); Compose: semantics(mergeDescendants = true)",A
12
+ Reduce Motion,reduce motion animation accessibility preference,Both,Settings > Accessibility > Motion > Reduce Motion; UIAccessibility.isReduceMotionEnabled,Settings > Accessibility > Remove animations; AnimatorDurationScale adb shell setting,Disable or simplify animations when Reduce Motion is enabled,"Check UIAccessibility.isReduceMotionEnabled / reduceMotionEnabled before starting animations; provide fade instead of slide; test with ReduceMotion on","Full navigation slide transitions even with Reduce Motion on; background micro-animations that distract (reduced continuously)","iOS: withAnimation(UIAccessibility.isReduceMotionEnabled ? .none : .spring()) {}; RN: AccessibilityInfo.isReduceMotionEnabled",AAA
13
+ Image Text Alternative,image icon decorative meaningful alt text description,Both,Accessibility Inspector: identify images without labels; VoiceOver reads 'image' for unlabeled,TalkBack: reads file name or 'unlabeled' for images without contentDescription; Lint 'ImageContrastCheck',"Every informational image needs alt text; decorative images must be hidden from screen readers","Write concise alt text (aim 0-150 chars); describe what the image conveys not what it looks like; hide decorative images","Alt text that repeats surrounding text; alt text 'image of...' (redundant); showing complex charts with no text alternative","iOS: Image('logo').accessibilityLabel('Company Logo').accessibilityHidden(decorative: false); Compose: Image(contentDescription='Profile photo')",A
14
+ Form Labels and Errors,form input label error message field validation,Both,VoiceOver: test each input navigating and activating; announce label + hint + error,TalkBack: input fields must announce label; errorMessage via setError() announced automatically,"Every input must have a persistent visible label; error messages must be associated with input; live announce on validation error","Use placeholder AND label (placeholder disappears on type); associate error message with field; announce when error appears/clears","Placeholder-only inputs (no persistent label); error shown visually only without announcement; generic 'Invalid' error without context","iOS: TextField('Name',text:$name).accessibilityHint('Enter your full name'); Android: TextInputLayout with setError()",A
15
+ Keyboard Navigation (Tablet),keyboard navigation bluetooth keyboard external tablet,Both,Simulate bluetooth keyboard navigation in Accessibility Inspector; hardware keyboard in simulator,Test with physical keyboard connected to Android tablet; TabChain and focus visualization,All interactive elements must be reachable and operable via keyboard on tablet,"Support Tab/Shift+Tab navigation; Enter/Space activates; Escape/Back dismisses panels; arrow keys navigate lists","Elements that can only be activated by touch not keyboard; no visible focus ring; Tab order different from swipe/visual order","iOS: keyboardShortcut(.tab, modifiers:[]); Compose: focusRequester(); HardwareBackHandler",A
16
+ Accessible Error Identification,error identification form field validation clear message,Both,VoiceOver: form error announcement; test submit with invalid data,TalkBack: setError() auto-announces; live region on error container,Error messages must describe what went wrong and how to fix it,"Error message: specific ('Password must be 8+ characters') not generic ('Invalid'); show in red AND with error icon symbol","'Error!' with no context; error only shown via color change; no instructions on how to fix","iOS: Text(errorMessage).foregroundColor(.red).accessibilityLabel(errorMessage); Android: TextInputLayout.setError('Password too short')",A
17
+ Reduce Transparency,reduce transparency blur frosted glass vibrancy,iOS,"Settings > Accessibility > Display & Text > Reduce Transparency; UIAccessibility.isReduceTransparencyEnabled","Not applicable — Android has no system-level transparency reduction setting","Reduce blur/vibrancy when Reduce Transparency is enabled — replace with solid background versions","Check isReduceTransparencyEnabled; use solid background color instead of UIBlurEffectStyle; test UI clarity without blur","All UI elements behind blur with no opaque fallback; navigation bar visible only through blur when disabled","UIBlurEffect: if reduceTransparency backgroundColor=systemBackgroundColor else useBlur",AAA
18
+ VoiceOver Rotor Navigation,voiceover rotor navigation headings links custom,iOS,VoiceOver Rotor (rotate two fingers): Headings Links Words Characters Custom Items; test all rotor categories,TalkBack Local Context Menu equivalent; TalkBack headings navigation,App content must be navigable by all rotor categories especially Headings and Links,"Add heading traits to section headers; ensure links have descriptive text; add Custom Rotor for app-specific navigation (search filters)","Navigation that only works by linear swipe; app with no headings making Headings rotor useless; custom rotor items with generic names","UIAccessibilityCustomRotor(name:'Tasks') { info in ... }; accessibilityAddTraits(.header)",A
19
+ TalkBack Explore by Touch,talkback explore touch finger feedback,Android,Not applicable — iOS uses different model,TalkBack Explore by Touch: hover finger over screen to hear items under finger; test all interactive elements are reachable,Every interactive element must be reachable by dragging finger around screen,"Test by enabling TalkBack and dragging finger across all interactive areas; ensure overlapping views don't block","Interactive elements covered by decorative overlay; custom touch regions that don't receive hover events in TalkBack","android:importantForAccessibility='yes'; Modifier.semantics { contentDescription = ... }; avoid clickable on containers",A
20
+ Accessible Rich Content,rich content data table chart graph accessible,Both,VoiceOver: tables navigated by row/column; charts announced as image by default; custom rotor needed,TalkBack: tables navigated by grid; charts need contentDescription or custom implementation,Charts and complex data must have accessible text alternative or accessible data table,"For charts: provide 'View as Table' button; for data tables: use proper table markup with headers; announce total trend in chart description","Image-only chart with no text alternative; data table with no row/column header association; interactive chart with no keyboard/accessible controls","iOS: List with ForEach for accessible table; chart + Button('View data as list'); Android: RecyclerView with table role",AA
21
+ Screen Reader Reading Order,reading order dom view order visual,Both,VoiceOver: swipe and confirm element reads in expected visual order,TalkBack: linearization audit; visualize focus via Developer Options > Show layout bounds check order,"Visual reading order (top-to-bottom LTR) must match swipe/focus order","Use semantic structure to control reading order; use accessibilitySortPriority to override; test flow with VoiceOver swipe","Absolutely positioned elements read in insertion order not visual order; content in wrong z-order reads out of sequence","iOS: .accessibilitySortPriority(100) for priority; Android: android:accessibilityTraversalBefore/After",A
22
+ Physical Touch Target Size (NNGroup),touch target physical 1cm minimum nngroup research study,Both,"Accessibility Inspector; measure on physical device with ruler — digital specs (pt/dp) don't communicate physical reality",AccessibilityScanner; test on actual device not emulator,"1cm × 1cm physical minimum (NNGroup / Parhi et al.); MIT Touch Lab: avg fingertip 1.6-2cm; avg thumb 2.5cm impact area; 44pt on 2x = ~7mm (BELOW 1cm — minimum is a compromise)","For apps used in motion (in-store walking driving): increase targets to 2cm×2cm; primary CTAs 2/3+ screen width; test on physical device not simulator where clicks are pixel-perfect","Designing touch targets that pass 44pt spec in Xcode but feel impossible on actual device; assuming simulator click accuracy equals real finger accuracy","Measure: 44pt on @3x = 44×3=132px at 3x ≈ 11mm ✓; 32pt on @3x = 32×3=96px ≈ 8mm ✗ below 1cm",AA
23
+ View-Tap Asymmetry Research,view tap asymmetry visible small tappable impossible,Both,"Test: can you accurately tap the element without hitting adjacent elements? Measure physical size","AccessibilityScanner; TalkBack Explore by Touch: dragging finger must land accurately on correct target","Elements that are readable/visible to eye but untappable accurately by finger — e.g. carousel dots (1-2mm), color swatches, pagination indicators","If an element is interactive it must pass 1cm physical tap target minimum — not just visible size; add invisible tap area extension if visual size must stay small","Carousel dot indicators as primary navigation without prev/next buttons; 6px × 6px pagination dots; tiny color swatches on product grids","iOS: ZStack { Dot().frame(8).padding(18) } // 8pt visual 44pt tappable; Android: View 8dp visual touchDelegate 48dp tappable",AA
24
+ Touch Target Spacing (Adjacent Errors),touch target gap spacing adjacent crowding slip error,Both,"Test rapid sequential taps on adjacent targets; observe error rate on physical device","AccessibilityScanner spacing check; manual test of adjacent action buttons","Minimum 8dp gap between adjacent interactive elements; elements that are same size but adjacent can still cause mistaps if gap <8dp","Space stacked action buttons 8-16dp apart; place destructive actions (Delete) far from safe actions (Save); for same-density layouts use single-target rows","Stacked buttons with 2dp gap (NNGroup Instagram dismiss failure study); Delete at same spacing as Edit in list row; icon buttons horizontally packed without gap","Minimum 8pt/dp between any two touchable regions; for error-sensitive pairs (delete/confirm) use 24pt+ separation",AA
25
+ Coach Mark Single Tip Rule,coach mark tip overlay single focused one at a time sequential,Both,"VoiceOver: announce when coach mark appears; is it focus-trapped? Can user dismiss with accessible action?","TalkBack: focus must move to coach mark tooltip on appearance; dismiss via back/swipe","Coach marks must be single-focused: one tip at a time; max 5 in entire onboarding sequence; tips must be dismissible and never block critical UI permanently","Show one coach mark at a time contextually; include visual arrow pointing to feature; use ultra-short copy <15 words; present at moment of first relevant action","Series of 8+ coach marks on first launch; tips that auto-dismiss in 1.5s leaving screen reader no time to read; coach mark shown every session","Announce appearance via live region; trap focus; provide custom accessibility action 'Dismiss hint'",AA
@@ -0,0 +1,22 @@
1
+ Animation Type,Keywords,Platform,Duration (ms),Easing,Do,Don't,Performance Impact,Reduced Motion Handling
2
+ Push Navigation Transition,push navigation transition screen slide stack,Both,350,ease-out cubic,"Slide new screen in from right; outgoing screen slides partially left (parallax offset); matches platform default","Custom transitions that fight platform direction (e.g., slide up for drill-down); excessive blur transitions on older devices",Low,Reduce: cross-dissolve/fade 150ms instead of slide; RN: Animated.timing with very short duration; SwiftUI: .transition(.opacity)
3
+ Pop Navigation Transition,pop navigation back swipe slide out,Both,350,ease-in cubic,"Slide current screen out to right; previous screen slides in from left; iOS: interactive swipe drives animation","Instant dismiss without animation; different direction than push (breaks mental model)",Low,Reduce: cross-dissolve 150ms; maintain direction consistency even in reduced motion
4
+ Modal Present (Sheet),modal sheet present slide up,Both,400,spring damping=0.85,"Slide sheet up from bottom with spring; dim background (scrim) fades in simultaneously; grab handle appears","Hard pop-in without spring (feels abrupt); slow over 500ms (feels laggy); no scrim (depth perception lost)",Low,Reduce: fade in 200ms instead of slide up; no spring animation
5
+ Modal Dismiss (Sheet),modal sheet dismiss swipe down,Both,300,ease-in,"Slide sheet down to bottom; scrim fades out simultaneously; proportional to swipe if gesture-driven","Hard snap-dismiss without slide out; faster than presentation (unbalanced); keep scrim after sheet gone",Low,Reduce: fade out 150ms; snap dismiss acceptable
6
+ Shared Element Transition,shared element hero transition image expand,Both,400,spring stiffness=300 damping=30,"Match source frame exactly → animate bounds to destination; fade crossfade overlapping views 150ms into transition; use matchedGeometryEffect (SwiftUI) or shared element (Compose Compose 1.7+)","Shared element on list with 20+ visible items (performance); mismatched bounds causing jump; skipping matching step",High — avoid with 20+ items in list,"Reduce: simple cross-dissolve 250ms between source and destination screens; remove hero animation; use modal scale instead"
7
+ Tab Switch Animation,tab switch bottom bar navigation transition,Both,200,ease-in-out,"Cross-dissolve between tab content; icon animates (scale 1→0.85→1 bounce for selected); color shifts to active","Slide animation between tabs (break mental model of peer sections); heavy transition for frequent action",Low,Reduce: no transition animation; instant tab switch; icon color change only
8
+ Page Swipe (Pager),page swipe horizontal pager scroll snap,Both,350,ease-out or spring (RN),"Track finger 1:1; snap to nearest page on release; page control dots update with scroll position","Page snap that's too fast (disorienting) or too slow (feels stuck); no snap (user stops on partial page)",Low,Reduce: instant page change on button press; disable swipe gesture on reduced motion page
9
+ Skeleton Shimmer,skeleton shimmer loading placeholder pulse,Both,1200,linear infinite loop,"Gradient sheen moves left-to-right repeating; 60% base color 100% highlight color; match content shape exactly","Fast/jarring shimmer; shimmer on already-loaded content; very high contrast shimmer colors",Low (CSS-like),Reduce: static placeholder without animation (just gray shape); no shimmer movement
10
+ Pull-to-Refresh Animation,pull to refresh spinner loading indicator gesture driven,Both,Variable: spinner 1000ms loop,"ease-out for pull; spring for release","Spinner tracks pull distance proportionally (0% → 100% revealed); snap to spinner position at threshold; haptic on threshold cross","Animating spinner before threshold; spinner that doesn't stop after data loaded; no haptic at trigger",Low,Reduce: instant trigger at pull threshold; minimal spinner; no elastic pull animation
11
+ List Item Appear,list items stagger fade appear loading content,Both,200-300 staggered 30ms per item,ease-out fade + translateY,"Items fade in + slide up 12-16pt; stagger 30ms between items (max 8 items staggered then instant after)","Animating 50+ items in sequence (janky); slow stagger that feels like loading delay; items appearing in wrong order",Medium — limit to <15 items,"Reduce: instant appear all items; no stagger; skip if list is refreshing existing content"
12
+ List Row Delete Swipe,list row delete swipe left action animation,Both,350,spring,"Row slides left revealing red action button; row collapses vertically on confirm delete 300ms ease-in-out; remaining items fill gap with spring","Hard snap at half-swipe; no collapse animation after delete (jarring content jump); delete without undo opportunity",Low,Reduce: highlight row briefly on delete; instant collapse without animation
13
+ Bottom Sheet Expand,bottom sheet drag expand collapse detent snap,Both,"Variable (drag) / 350 snap",spring damping=0.75,"Track drag 1:1; snap to nearest detent on release; velocity-aware snap (fast swipe → skips to next detent); dimmer intensity proportional to sheet height","Snapping without spring (stiff); not following finger 1:1 during drag; dimmer that doesn't track sheet height",Low,Reduce: fade in at target detent directly; no drag-proportional animation
14
+ State Change (Toggle Switch),toggle switch state change on off,Both,200,spring bouncy for iOS / ease-out for Android,"Thumb slides smoothly; track fills/empties with color; haptic at toggle point","Instant state change without animation (mechanical feel); very slow toggle (>300ms) that delays interaction",Low,Reduce: instant visual state change; maintain haptic even in reduced motion (haptic ≠ animation)
15
+ Loading Spinner,spinner activity indicator circular loading,Both,1000 per rotation loop,linear (constant velocity),"System-default spinner with spinner color matching brand; show after 300ms content delay (avoid flash for fast loads)","Custom spinner that's too complex (distracts); not showing completion state; infinite spinner for determinate progress",Low,"Reduce: static 'Loading...' text label; don't animate; notify completion via live region announcement"
16
+ Success Microinteraction,success checkmark confetti celebration complete,Both,600,spring + scale,"Checkmark draws with spring animation 400ms; optional brief scale pop (1→1.08→1 200ms spring); haptic .success; disappears after 2s or on next interaction","Overlong celebration (>800ms) blocking next action; confetti for minor routine tasks; no haptic with visual success",Low,Reduce: static checkmark icon; no animation; haptic still appropriate
17
+ Error Shake,error shake validation input wrong password field,Both,400 total (4 oscillations),spring sinusoidal,"Horizontal shake ±8pt with 4 rapid oscillations; haptic .error simultaneously; error text appears below field with fade-in","Gentle barely-visible shake (unclear); vertical shake (non-standard); shake without haptic; shake for warnings (reserve for errors)",Low,Reduce: static error border color + error text; no shake; haptic still appropriate for .error
18
+ FAB Morphing Extended,fab extended morph expand collapse action,Android,250,ease-in-out standard,"Small FAB expands to Extended FAB (icon left + label right) on scroll up / collapse on scroll down; icon crossfades during expansion","Morphing so fast text isn't readable; morphing for every scroll event (debounce); morphing on iOS (no native FAB)",Low,Reduce: instant state switch between small/extended FAB without animation; label appears/disappears instantly
19
+ Keyboard Slide Adjustment,keyboard keyboard appear input push content animation,Both,250 matches system keyboard,same as system,"Scroll view or container adjusts upward as keyboard slides in; proportional to keyboard height; no delay","Custom keyboard offset that doesn't match keyboard timing (content slides before keyboard appears); abrupt jump","Low — driven by system keyboard notification","Reduce: system keyboard animation is already minimal; key is ensuring content is still reachable above keyboard"
20
+ Haptic-Visual Synchronization,haptic visual sync simultaneous feedback confirm,Both,<16ms offset between visual and haptic,N/A — must be simultaneous,"Trigger visuals and haptics within same frame (16ms); use UIImpactFeedbackGenerator.impactOccurred() and UI update in same cycle","Haptic delayed 200ms after visual change (breaks sensation of physical response); haptic without any visual feedback",Low,Reduce: haptic still appropriate even in Reduce Motion; only animations are reduced not haptics
21
+ Lottie Animation,lottie animation json vector complex animation,Both,Variable per asset,Asset-defined in JSON,"Use for complex illustrations onboarding empty states success states; 120fps capable; dark mode variants via design tokens","Lottie for simple spinners or loading (use system default); 10MB+ animation files; autoplaying ambient animations in loops",Medium — preload asset,"Reduce: show first or last frame as static image; LottieAnimationView.setSpeed(0); Lottie has reduceMotion property"
22
+ Page Indicator Dot,page indicator dot pager swipe transition,Both,150 per dot transition,ease-out,Active dot expands slightly (8→10pt) with color fill; inactive dots are smaller outline; cross-fade on page change,"Custom shapes that aren't dots (confusing); dots that don't update live during swipe; hiding indicator with >3 pages",Low,Reduce: dots still update position but without transition animation; instant state change
@@ -0,0 +1,21 @@
1
+ Component Name,Keywords,Platform Variants,Purpose,Do,Don't,Haptic Feedback,Animation Spec,Accessibility
2
+ Bottom Sheet,bottom sheet modal sheet overlay panel,iOS: UISheetPresentationController; Android: ModalBottomSheet (MD3),Present secondary content without losing context (filters actions details media),"Use grab handle to hint draggability; support swipe-to-dismiss; provide scrim for modal variant","Block full screen unnecessarily; use for primary navigation; open bottom sheets from bottom sheets (stack)",Optional: impact on expand,Expand: 300ms ease-out spring; Dismiss: 250ms ease-in,Announced as 'popup'; focus moves to first element; background covered by scrim prevents interaction; swipe-down dismisses for VoiceOver
3
+ Floating Action Button (FAB),fab floating action button primary create add action,iOS: No native — use custom; Android: FAB / Extended FAB / Small FAB (MD3),Trigger primary screen action (create compose record add),Single FAB per screen; position bottom-right; use extended FAB with label for clarity,"Multiple FABs on one screen; use for navigation (use tab bar); hide behind other content",Impact on press,Scale 0.95 on press 80ms; appear with scale+fade 300ms,Required: accessibilityLabel describing action not just icon; tooltip on long press; 'Button' role implied
4
+ Snackbar,snackbar toast notification brief message undo action,iOS: Custom (no native Snackbar); Android: Snackbar (MD3),"Brief feedback message after action; optional single action (Undo); auto-dismissing","Auto-dismiss after 4s; one action max (Undo); position above nav bar; avoid stacking","Block user; show errors (use Alert/Dialog); show while keyboard is open (obscures content)",None,Appear: 250ms slide up; Dismiss: 200ms fade out,"Announced via accessibility live region; action button fully accessible; avoid timing-out before user reads (extend on focus)"
5
+ Alert Dialog,alert dialog popup confirm destructive warning,iOS: UIAlertController (.alert style); Android: AlertDialog / BasicDialog (MD3),Confirm destructive actions; present critical decisions requiring immediate response,"Keep to 2 actions (max 3); title required; positive action = rightmost on iOS","Auto-dismiss; present non-critical info (use snackbar); use for long content (use full sheet)",Impact on appear,Pop-in: scale 0.95→1 + fade 200ms; Dismiss: 150ms fade,Focus moves to dialog; background blocked; title read on appear; button labels must be self-explanatory; Escape/back = cancel
6
+ Action Sheet,action sheet bottom options ios share menu,iOS: UIAlertController (.actionSheet); Android: ModalBottomSheet with list (MD3),"Present 3-8 contextual options; share menu; 3-dot menu expansion","Include Cancel option; group related actions; destructive action in red at bottom (iOS)","Show more than 8 options (use full sheet list); replace modal navigation; show on first launch",Light impact on appear,Slide up 250ms ease-out; Cancel tap: slide down 200ms,Each option fully accessible; sheet announced as 'action sheet'; Cancel always first focus OR bottom most
7
+ Skeleton Loader,skeleton loading shimmer placeholder loading state,iOS: Custom; Android: Shimmer / Lottie / Custom Compose,Indicate content is loading while preserving layout,"Match final content dimensions; animate shimmer 1-1.5s loop; display after 200ms delay","Show for <200ms loads (just show content); display after content loads; use for unknown content shapes",None,Shimmer animation 1200ms linear infinite horizontal gradient,Announce 'Loading' to screen readers; transition to 'loaded' announced; avoid jarring content shift after load
8
+ Pull-to-Refresh Indicator,pull to refresh indicator spinner loading refresh,iOS: UIRefreshControl; Android: SwipeRefreshLayout / PullRefresh Compose,Signal that a manual data refresh is in progress,"Use standard system controls; provide haptic on trigger; return to top after refresh","Trigger refresh automatically on scroll (user expectation violation); use for initial load (show skeleton)",Light impact on trigger,Expand on pull proportional to pull distance; spinner after threshold cross,Add manual refresh button for accessibility; announce 'refreshing' and 'refreshed' via live region
9
+ Search Bar,search bar input filter search field search,iOS: UISearchBar / UISearchController; Android: SearchBar + SearchView (MD3),Filter content or trigger search flow,"Activate on tap; show cancel/clear button; preserve query on back","Auto-submit on every keystroke (debounce 300ms); hide below fold; force full-screen overlay for simple filter",None,Expand from icon: width 250ms ease-out; suggestions appear 150ms fade,Label: 'Search field'; hint text read as placeholder; clear button labeled 'Clear search'; results count announced
10
+ Navigation Bar (iOS),navigation bar top bar app bar title back,iOS: UINavigationBar; Android: TopAppBar (MD3),Display current screen title and actions (back edit share search),"Large title on root level; standard title on drill-down; 2-3 actions max right side","Overload with many buttons (3+ right); use for primary content; custom heights that break system behavior",None,Cross-dissolve title transition on push 300ms; large-to-standard title collapse on scroll,"Title announced on screen push; back button accessible; buttons described with labels not just icons"
11
+ Context Menu (Long Press),context menu long press preview peek actions,iOS: UIContextMenuInteraction; Android: PopupMenu / ContextMenu,Provide quick access to item-level actions without navigating away,"Include preview when meaningful; max 5-7 items; organize with separators","Show for primary actions (use buttons); auto-open on load; duplicate main screen actions unnecessarily",Light impact on open,Preview scale pop 0.98→1 250ms spring; menu fade-in 150ms,"'Actions' available via VoiceOver double-tap-hold or swipe up for actions; each action labeled; dismiss on Escape/back"
12
+ Badge / Notification Dot,badge notification count dot unread indicator,iOS: UITabBarItem.badgeValue; Android: MaterialBadge (MD3); NotificationBadge,Indicate unread count or new activity without interrupting user,"Show meaningful count; cap at 99+; red for urgent neutral for info","Animate badge on every update (distracting); badge decorative information; show exact count over 999",None,Badge appear: scale 0 → 1 bounce 200ms spring; count change: brief pulse 150ms,"Badge value announced with context: '3 unread, Inbox'; dot badge: 'New content in [tab name]'"
13
+ Progress Bar / Indicator,progress bar loading indicator progress determinate indeterminate,iOS: UIProgressView / UIActivityIndicatorView; Android: LinearProgressIndicator / CircularProgressIndicator (MD3),Communicate loading or task progress status,"Determinate (known duration); indeterminate (unknown); show after 500ms threshold","Show for instant operations; use spinner for indefinite but short waits; block UI unnecessarily",None,"Determinate: animate value change 300ms ease-in-out; Indeterminate: infinite 1200ms cycle loop","Progress value announced as percentage; label describes task: 'Uploading photo, 60%'; complete state announced"
14
+ Tab Bar Item,tab bar item icon label badge indicator,iOS: UITabBarItem; Android: NavigationBarItem (MD3),Represent a top-level section in the tab bar navigation,"Icon + label both visible; 44pt touch target; 2-5 items","Text-only tabs (iOS HIG); icon-only without label (Android MD3 recommends labels); more than 5 items",Selection: selection haptic light,Selected state: color shift 100ms ease; badge bounce 200ms spring on appear,"Label + icon announced: 'Home, tab 1 of 5'; selected state: 'Home, selected'; badge: '3 unread, Home, tab 1 of 5'"
15
+ Chip,chip filter tag label pill selectable removable,iOS: Custom pill; Android: AssistChip FilterChip InputChip SuggestionChip (MD3),Compact elements for filters input tags or suggestions,"Wrap chips to multiple rows if needed; min 32pt/40dp height; group related chips","Chips for navigation (use tabs); primary actions (use button); make too small to tap",Selection: light haptic,Selected: background color fill 100ms; deselect: 100ms reverse,Chip type/role announced; selected state announced; removable chips: X button labeled 'Remove [chip name]'
16
+ Empty State,empty state no content zero state first use,iOS: Custom; Android: Custom (no standard component),Communicate when a list or screen has no content and guide next action,"Illustrate the empty scenario; include primary CTA to fill the gap; friendly copy","Show empty state during loading; use generic 'No results' without guidance; sad/error message for expected-empty",None,Fade in after data confirmed empty 300ms; illustration entrance from bottom 250ms ease-out,Announce 'No items' with context; CTA button accessible; avoid emoji-only illustration (no text alternative)
17
+ Toast (Android),toast android toast brief message auto-dismiss,iOS: Custom; Android: Toast (legacy) / Snackbar (preferred MD3),"Very brief non-actionable system message; background app events; legacy pattern (prefer Snackbar)","Use Snackbar instead; auto-dismiss 2-3.5s short; app-wide usage only","Use Toast for important messages (use Snackbar with action); show from Activity after activity finishes",None,Appear: fade in 150ms; Dismiss: fade out 150ms,"Announced via accessibility live region; no action possible — use Snackbar if action needed; prefer Snackbar for all new code"
18
+ Segmented Control,segmented control segment toggle switch view mode,iOS: UISegmentedControl; Android: SegmentedButton (MD3),Toggle between 2-5 mutually exclusive view modes or options,"Use for immediate effect (not form submission); 2-4 options ideal; equal width segments","Navigation between screens (use tabs); more than 5 segments; use for binary on/off (use Switch)",Light haptic on segment change,Selected segment: 200ms fill transition; pressed: 50ms scale 0.97,"'Segmented control' role; selected value announced; options count: '3 options, Photos selected'"
19
+ Switch / Toggle,switch toggle on off setting preference binary,iOS: UISwitch; Android: Switch (MD3),Enable or disable a single setting or feature,"Label left or above toggle; show immediate effect; confirm destructive toggles","Multi-toggle without context; use as confirmation substitute (use modal); no label",Light haptic on toggle,Thumb slide: 250ms spring ease; track color: 150ms ease,State announced on change: 'Dark mode, on' / 'off'; label read before state; role: 'switch'
20
+ Image Picker,image picker photo gallery camera media select,iOS: PHPickerViewController / UIImagePickerController; Android: Photo Picker (Android 13+); ActivityResultApi,Let user select photo or video from library or capture new,"Use system picker for privacy; support multiple selection if needed; preview before upload","Build custom gallery (permissions implications); access all photos without PHPickerViewController (iOS)","Use PHPicker (no permission needed for selection); check Info.plist keys for camera","Use Photo Picker API (no storage permission on Android 13+); camera needs CAMERA permission","System pickers are accessible; custom pickers need full accessibility implementation: image labels grid nav"
21
+ Pull-Down Menu,pull-down menu dropdown button menu ios,iOS: UIMenu on UIButton (iOS 14+); Android: DropdownMenu (MD3),Show list of options anchored to a button,"Show 3-8 options; include icons for quick scanning; use separator between groups","Too many options (use full sheet); primary single action (just use button); on Android prefer DropdownMenu MD3",Light on menu open,Menu appear: 150ms scale from anchor + fade; Dismiss: 100ms fade out,"Button announces 'shows menu' as hint; menu items announced; checkmarks read as 'selected'; Escape/back dismisses"
@@ -0,0 +1,26 @@
1
+ Gesture Name,Keywords,Platform,Trigger,Expected Response,Conflicts,iOS Hint,Android Hint,Accessibility Alternative
2
+ Tap,tap touch select activate click,Both,Single finger tap on element,Activates button / selects item / opens link,Double tap (zoom); Long press (context menu),"UITapGestureRecognizer; minimum 44×44pt target","ClickListener; minimum 48×48dp target; ripple feedback",Use standard button/link elements — automatically activatable by screen reader
3
+ Double Tap,double tap zoom accessibility magnify,Both,Two quick taps same element,"Zoom in map/image; Like action (social); re-focus","Tap; Triple tap (VoiceOver navigation)","UITapGestureRecognizer numberOfTapsRequired=2; MKMapView zoom","GestureDetector.onDoubleTap; MotionEvent.ACTION_DOWN x2","Not recommended as primary action — VoiceOver uses double tap for activation; provide tap alternative"
4
+ Long Press,long press hold press haptic context menu,Both,Hold finger on element 500ms+,"Context menu appears; drag enablement; haptic feedback; copy/paste","Scroll (drag starts); Force Touch (iOS)","UILongPressGestureRecognizer; minimumPressDuration 0.5s; UIContextMenuInteraction","GestureDetector.onLongPress; HapticFeedbackConstants.LONG_PRESS; PopupMenu anchor","VoiceOver 'Actions' menu replicates long press; Android: long press must have keyboard/TalkBack equivalent"
5
+ Swipe Left (List Action),swipe left list action delete archive dismiss,Both,"Horizontal swipe left on list item >30% width","Reveals delete / archive / action buttons","Scroll (if threshold not met); Swipe right","UISwipeActionsConfiguration; UITableView trailingSwipeActions; reveal destructive red action","ItemTouchHelper; SwipeToDismiss in Compose; swipeableItem Compose","TalkBack 'Actions' menu provides delete/archive without swipe; announce available actions on focus"
6
+ Swipe Right (List Action),swipe right list action archive mark read,Both,"Horizontal swipe right on list item","Reveals leading action (archive mark-read flag)","Scroll; Swipe left","UITableView leadingSwipeActions; non-destructive green/blue action","ItemTouchHelper.RIGHT; Compose swipeableItem leading","TalkBack: 'Actions' menu for same actions; leading actions less discoverable — ensure TalkBack alternative"
7
+ Pull to Refresh,pull to refresh refresh reload swipe down top,Both,Pull list downward from very top (beyond scroll start),"Loading indicator appears; content refreshes","Overscroll effect; Drag from top","UIRefreshControl; attach to UIScrollView; spinner + message","SwipeRefreshLayout; PullRefresh in Compose; RefreshIndicator in Flutter","Not accessible via TalkBack/VoiceOver by default — add a refresh button always; announce 'refreshed' when done"
8
+ Swipe to Dismiss (Modal),swipe down dismiss modal sheet close,iOS,"Swipe modal/sheet downward from anywhere / drag handle","Modal closes / sheet collapses to smaller detent","Scroll content within modal","UISheetPresentationController; isModalInPresentation prevents dismiss; grabber visible","Not standard on Android — use close button or scrim tap","Modal close button (X/Done) is the accessible path; announce 'dismissed' on close"
9
+ Edge Swipe Back (iOS),edge swipe back iOS navigation gesture return,iOS,"Swipe right starting from left edge of screen","Navigates back to previous screen with push animation","Overlapping horizontal scroll at screen edge","interactivePopGestureRecognizer; enabled by default in UINavigationController; can conflict with side drawers","Not applicable — Android uses system back","Fully supported by VoiceOver navigation as 'back'; no extra work needed; conflicts with drawer swipe — choose one"
10
+ Android Back Gesture,android back swipe predictive gesture system,Android,"Swipe inward from either screen edge (Android 13+)","Returns to previous screen; predictive back preview shows destination (API 34+)","Edge scroll; Drawer open gesture","Not applicable on iOS","Enable predictive back: android:enableOnBackInvokedCallback=true; handle in onBackPressedDispatcher","System-level — fully accessible via TalkBack; predictive back shows visual preview"
11
+ Pinch to Zoom,pinch zoom scale expand collapse two finger,Both,Two fingers move apart (zoom in) or together (zoom out),"Scales content (map image PDF); zoom level changes","Rotate gesture (similar two-finger)","UIPinchGestureRecognizer; min/max scale limits; spring-back to bounds","ScaleGestureDetector; pinchable modifier in Compose","Add zoom in/out buttons as alternative; screen reader users cannot do multi-touch; announce zoom level"
12
+ Rotate,rotate two finger turn orientation,Both,"Two fingers rotate clockwise/counter-clockwise","Rotates image / map orientation","Pinch (similar two-finger starting point)","UIRotationGestureRecognizer; use alongside pinch for image editors","RotateGestureDetector; combine with ScaleGestureDetector","Must have button alternative for rotation; announce rotation angle in degrees"
13
+ Pan / Drag,pan drag move position scroll,Both,"One finger hold and move","Drags element to new position; scrolls content","Long press start confusion; swipe actions at edge","UIPanGestureRecognizer; UIDragInteraction for drag-and-drop","GestureDetector.onPanUpdate; draggable Modifier in Compose","Drag-and-drop requires keyboard/accessibility alternative per WCAG 2.5.7; announce new position on drop"
14
+ Scroll,scroll vertical horizontal swipe momentum,Both,"One finger swipe on scrollable area","Content scrolls in swipe direction; momentum continues after lift","Swipe actions (conflicting thresholds); Pull to refresh","UIScrollView; scrollsToTop on status bar tap; bounce effect","NestedScrollView; fling velocity; OverScroll effect","Keyboard arrow keys on large screens; scroll position announced by VoiceOver as percentage; snap points announced"
15
+ Two-Finger Scroll,two finger scroll accessibility scrolling,iOS,"Two fingers swipe on screen","VoiceOver: scrolls content; non-VoiceOver: not typically used","One finger scroll conflicts","Used by VoiceOver for scrolling when element is focused; not a custom gesture","TalkBack: two-finger scroll is a system gesture too","This IS the accessibility path — do not override or intercept two-finger scroll"
16
+ Three-Finger Tap,three finger tap undo redo ios text,iOS,"Three fingers tap once","Undo typing (iOS); app-level undo if implemented","Two-finger tap; Triple tap","Shake to undo is alternative; three-finger double-tap = redo","No equivalent on Android","VoiceOver uses three-finger gestures for navigation — never override three-finger gestures"
17
+ Shake to Undo,shake undo motion gesture accelerometer,Both,"Device shaking motion","Undo last text input action (iOS); custom app-wide undo","Accidental shakes (low threshold = false positives)","UIResponder.motionBegan(.shake); enabled by default for text; canBecomFirstResponder required","Not standard; custom via SensorManager","Shake is not accessible (users with motor impairments); always provide an undo button as alternative"
18
+ Force Touch / Haptic Peek,force touch 3d touch haptic peek preview,iOS,"Deep press on iOS device with 3D Touch (older iPhones)","Preview popup (Peek); release to open (Pop); swipe up for actions","Long press (use long press as fallback; 3D Touch deprecated)","availableHapticFeedbackTypes; UIPreviewAction; deprecated in iPhone 11+; replaced by long press","Not available on Android","Long press is modern iOS fallback and is fully accessible; 3D Touch had no accessibility equivalent"
19
+ Swipe Between Pages,swipe horizontal pages pager swipe left right,Both,"Full-width horizontal swipe on page","Navigates to adjacent page; page indicator updates","Tab switching; Carousel scroll","UIPageViewController; UIScrollView.isPagingEnabled; SwiftUI TabView + .page style","ViewPager2; HorizontalPager in Compose; scroll snap CSS-like","Add prev/next buttons as accessible alternative; announce page number and total; 'Page 2 of 5'"
20
+ Pinned-Section Scroll,sticky header section pin scroll,Both,"Scrolling past section boundary","Section header sticks to top while section content scrolls underneath","Standard scroll","UICollectionView compositional layout section header pinned","StickyHeader in LazyColumn via stickyHeader {}; LazyListState","Announce section name when pinned header changes; VoiceOver navigates by heading if marked as header"
21
+ Scroll to Top,scroll top status bar tap,iOS,"Tap on iOS status bar","Scrolls content to very top instantly",None — status bar area reserved,"UIScrollView.scrollsToTop = true (default); only works on topmost scroll view","No equivalent — add scroll-to-top FAB button on Android","Accessible via VoiceOver quick nav to top; Android needs explicit button"
22
+ Drag to Reorder,drag reorder list long press drag handle,Both,"Long press on list item then drag to new position","Item moves with finger; other items shift to accommodate","Long press context menu (resolve by drag handle icon to distinguish)","UITableView moveRow; UICollectionView drag-and-drop delegate","ItemTouchHelper.Callback; ReorderList in Compose","WCAG 2.5.7: must have button-based reorder alternative (move up/down); announce position on drop 'Item moved to position 3'"
23
+ Scroll Momentum / Fling,fling momentum inertia scroll fast swipe,Both,"Fast swipe releases with velocity","Content continues scrolling with deceleration; snaps to near item if snap enabled","Scroll to trigger pull-refresh (slow vs fast swipe)","UIScrollView.decelerationRate (.normal .fast); paging mode snaps to page","RecyclerView SnapHelper; fling threshold velocity","Motion sensitivity: respect reduceMotion — disable momentum for high-motion users if possible"
24
+ Haptic Feedback,haptic taptic feedback vibration touch response,Both,"Programmatic response to user action","Subtle vibration confirms action (selection impact notification)","Overuse desensitizes; avoid on every tap","UIImpactFeedbackGenerator (.light .medium .heavy .rigid .soft); UISelectionFeedbackGenerator","HapticFeedbackConstants; performHapticFeedback; VibratorManager API 31+","Cannot be configured to be 'accessible-only'; some users have reduced haptics enabled; never use as only feedback"
25
+ Pinch Zoom Map,pinch zoom map pan map rotate map,Both,Pinch/pan/rotate on map element,Map zooms / pans / rotates to new viewport,None within map bounds,"MKMapView handles gestures natively; MapKit SwiftUI or UIKit","Google Maps / MapBox Android handles natively","Add +/- zoom buttons and compass button for accessible map control; announce map region changes"
26
+ Context Menu via Accessibility,voiceover actions talkback long press context menu accessibility,Both,"VoiceOver: swipe up for 'Actions' menu; TalkBack: long press or swipe down for context menu","Shows accessible alternative to long-press / swipe gestures",None,"accessibilityCustomActions: [UIAccessibilityCustomAction]; labels must be descriptive","contentDescription + ViewCompat.addAccessibilityAction(); custom actions in semantics Compose","This IS the accessibility implementation — always define custom actions for any gesture-based UI"
@@ -0,0 +1,21 @@
1
+ Topic,Keywords,Platform,Rule,Value/Spec,Do,Don't,Code Example
2
+ Safe Area Top,safe area top notch status bar inset,iOS,"Respect the top safe area inset (notch / Dynamic Island / status bar); never place interactive content behind it","Top safe area: 20pt (non-notch) / 47-59pt (notch/Dynamic Island depending on device)","Add padding/inset equal to safeAreaInsets.top; use ignoresSafeArea(.all) only for background images","Place buttons or text behind notch; use fixed top padding values (device-dependent)",.ignoresSafeArea(edges:.top) for backgrounds only; safeAreaInsets.top for content
3
+ Safe Area Bottom,safe area bottom home indicator inset navigation bar,iOS,"Respect bottom safe area (home indicator on Face ID phones); ensure actions aren't hidden behind it","Bottom safe area: 0pt (home button)/ 34pt (Face ID screen)","Add padding equal to safeAreaInsets.bottom for any floating buttons or tab-bar-adjacent content","Hardcode 34pt (varies by device); hide content behind home indicator area; overlap tab bar",Modifier: .padding(.bottom, geometry.safeAreaInsets.bottom)
4
+ Android Navigation Bar Inset,android navigation bar inset gesture nav,Android,"Respect WindowInsets for both 3-button navigation and full gesture navigation bar; content should not be behind nav bar","Navigation bar height: ~48dp (3-button) / 0dp visible but gesture zone still active (~32dp swipe zone)","Use WindowCompat.setDecorFitsSystemWindows(false) + ViewCompat.setOnApplyWindowInsetsListener; use windowInsetsController","Hardcode 48dp (gesture nav makes it 0); use deprecated fitSystemWindows=true",ViewCompat.setOnApplyWindowInsetsListener; Modifier.windowInsetsPadding(WindowInsets.navigationBars)
5
+ Minimum Touch Target,touch target minimum size tap area finger,Both,"Minimum tappable area 44×44pt (iOS) / 48×48dp (Android); padding can extend hit area beyond visual size","iOS: 44×44pt; Android: 48×48dp; Google recommends 56×56dp for high-frequency targets","Use padding to extend touch area while keeping visual size smaller; test with finger not mouse","Make icon-only buttons 20×20pt visually without padding; rely on small thin text links as only actions",iOS: frame(minWidth:44,minHeight:44); Android: minimumTouchTargetSize(48.dp) in Compose
6
+ Content Margins,content margins safe horizontal padding edges,Both,"Maintain consistent horizontal margins so content isn't flush with screen edge; prevents thumb-zone issues","iOS HIG: 16pt minimum side margin; Material Design: 16dp (compact) / 24dp (medium) / 24dp+ (expanded)","Use consistent margin tokens across screens; scale margins for larger screens (tablet)","Zero margins on important content; different margins on same screen for same content type","iOS: .padding(.horizontal, 16); Android: Modifier.padding(horizontal = 16.dp)"
7
+ Thumb Zone,thumb zone reachability one hand bottom reach ergonomics,Both,"Place primary interactive elements within comfortable one-handed thumb reach; bottom 60% of screen","Easy reach zone bottom: ~75% of screen height from bottom; Difficult zone: top 25% of screen","Put primary CTA near bottom; tab bars at bottom; floating buttons bottom-right; critical actions mid-screen","Place primary actions at very top of screen (thumb stretch); right-handed bias for destructive actions",Consider screen height: 812pt (iPhone SE small) to 932pt (iPhone 14 Pro Max)
8
+ Dynamic Island,dynamic island notch live activity,iOS,Design around Dynamic Island (iPhone 14 Pro+); content must flow around it not under it,"Dynamic Island dimensions: ~37pt tall × 120pt wide inactive / expands per Live Activity","Check device model before assuming notch dimensions; use safeAreaInsets.top which already accounts for it","Assume all iPhones have same notch; animate content overlapping Dynamic Island area","safeAreaInsets.top already includes Dynamic Island height; Live Activities API for integration"
9
+ Keyboard Avoidance,keyboard avoid text input scroll push,Both,"When keyboard appears push content up so focused input remains visible; avoid covering input fields","Keyboard height: 250-330pt on iPhone (varies by locale and keyboard type)","Use KeyboardAvoidingView (RN) / Scaffold imePadding (Compose) / .ignoresSafeArea(.keyboard,edges:.bottom) negation","Hardcode offset; let keyboard cover inputs; use full-screen for forms without scroll support","iOS SwiftUI: .ignoresSafeArea(.keyboard); RN: KeyboardAvoidingView behavior='padding'"
10
+ Scroll Indicator,scroll indicator scrollbar visibility content hint,Both,"Show scroll indicators when content exceeds viewport; they quickly communicate 'more content below'","Thumb height proportional to content ratio; system-standard thin line indicator; auto-hides","Allow default system scroll indicators; use scroll position to show/hide sticky elements","Hide scroll indicators for long content; custom scroll indicators that don't match platform style","showsVerticalScrollIndicator={true} (RN); showsVerticalScrollIndicator in SwiftUI ScrollView"
11
+ Landscape Layout,landscape orientation rotation responsive layout,Both,"Handle landscape rotation gracefully; content should reflow not just scale; avoid sidebar being empty","Landscape typically gives 1.77× width, 0.56× height","Test both orientations; use split view or extra columns on landscape landscape; constrain rotation if needed","Force portrait only without UX reason; crash on rotation; duplicate nav controls without hiding portrait ones","SwiftUI: .supportedInterfaceOrientations; Compose: rememberWindowSizeClass()"
12
+ Fold Screen,fold screen foldable inner outer display,Android,"Support foldable devices (Galaxy Z Fold Samsung); app must adapt when fold state changes","Fold hinge: ~30dp logical width; posture can be FLAT/HALF_OPENED; inner display ~7.6 inches","Use WindowInfoTracker to detect fold state; multi-pane layout when unfolded; single pane when folded","Ignore fold and scale same layout; place content in fold hinge area; assume fixed dimensions","WindowInfoTracker.getOrCreate(context); FoldingFeature API; Jetpack Window Manager"
13
+ Status Bar,status bar style color appearance,Both,"Status bar appearance must contrast with content behind it (dark on light / light on dark backgrounds)","Status bar height: 20pt (iOS non-notch) / 44-59pt (notch variants) / 24-30dp (Android)","Set preferredStatusBarStyle; use system-adaptive status bar color; hide status bar only for immersive full-screen","White status text on white background; hide status bar in main app flows; force one style for all screens","iOS: UIStatusBarStyle / preferredStatusBarStyle; Android: WindowInsetsController.setSystemBarsAppearance"
14
+ Spacing Scale,spacing scale margin padding design tokens,Both,"Use a consistent spacing scale (8pt grid on iOS; 4dp/8dp grid on Android MD3); avoid random spacing values","4dp base unit (MD3); 8pt base unit (iOS HIG); spacings: 4 8 12 16 20 24 32 40 48dp","Define spacing tokens; use multiples of 4 or 8; consistent spacing for same component types","Arbitrary spacing values (17px 23px); different spacing for semantically same layout on different screens","Define spacing: small=8 medium=16 large=24 xlarge=32; use consistently"
15
+ Content Width Limit,content width max readable line,Both,"Limit readable text content to 45-75 characters per line for comfortable reading; use max width on large screens","Ideal: 55-66 chars/line; max container width on tablet: ~600-840dp; text line: 360dp max","Constrain text containers with maxWidth; let images use full width; add horizontal padding on tablet","Full-width text on 10-inch tablet (75+ chars per line); center-align long paragraphs",".frame(maxWidth: 600) SwiftUI; .widthIn(max = 600.dp) Compose; maxWidth: '600px'"
16
+ Corner Radius,corner radius rounded corners card surface,Both,"Match corner radius to platform conventions; iOS prefers more rounded corners; MD3 uses shape tokens","iOS typical: 12-16pt (cards) 10pt (buttons) 8pt (small chips); MD3: ExtraSmall=4dp Small=8dp Medium=12dp Large=16dp ExtraLarge=28dp","Use shape tokens from theme; be consistent across similar-sized components; match system alerts","Different corner radii for same component type throughout app; iOS style extreme pill radius on Android",".clipShape(RoundedRectangle(cornerRadius:16)); .clip(MaterialTheme.shapes.medium) Compose"
17
+ Text Contrast,text contrast color readability,Both,"Body text must meet WCAG AA contrast ratio 4.5:1 against background; large text (18pt+ or 14pt bold+) 3:1","WCAG AA: 4.5:1 normal / 3:1 large; WCAG AAA: 7:1 normal / 4.5:1 large; target 4.5:1 minimum","Test contrast for light AND dark mode; dynamic type doesn't change color ratio but view contrast in context","Light gray text on white background; placeholder color for body text; 'close enough' approximations","Use Accessibility Inspector (Xcode) / Compose accessibility audit / Color Contrast Analyzer tool"
18
+ Elevation and Shadow,elevation shadow depth layer z-index,Both,"Use elevation/shadow to communicate hierarchy and interactivity; bottom sheets higher than content","iOS: system shadow (shadowColor opacity radius offset); MD3: elevation system 0/1/2/3/4/5 (dp surface tint)","Subtle shadows for cards (2-4dp); higher elevation for sheets and dialogs (8-24dp); shadow matches platform","Strong harsh shadows on iOS (use subtler); ignoring elevation system in Android MD3; mixing shadow styles","iOS: .shadow(color:.black.opacity(0.1),radius:4); Compose: CardDefaults.cardElevation(defaultElevation=8.dp)"
19
+ Grid Layout,grid columns responsive masonry layout,Both,"Use grids for visual consistency in image galleries product listings or icon grids; column count adapts to screen width","Phone portrait: 2-3 cols; Phone landscape: 4 cols; Tablet: 4-6 cols; minimum cell size 100pt","Calculate column count dynamically from screen width; equal gutters between cells; aspect ratio consistency","Fixed column count that doesn't adapt to screen size; inconsistent gutter widths; overflow cells","LazyVGrid(columns:[GridItem(.adaptive(minimum:150))]) SwiftUI; LazyVerticalGrid Compose"
20
+ List Row Height,list row cell height minimum size touching,Both,"List rows must be large enough to be easily tappable; rich content rows taller; simple text rows minimum 44pt","Simple text: 44pt minimum; with subtitle: 60pt; with image: 60-80pt; always verify touch target","Include visual breathing room within row (16pt vertical padding); align content to 8pt grid","Tiny rows users can barely tap; rows without internal padding that feel cramped","UITableView.rowHeight; minimumRowHeight; Compose itemContent padding(vertical=16.dp)"
21
+ Notch and Camera Cutout,notch camera cutout punch hole display edge,Both,"Modern phones have camera cutouts (notch Dynamic Island punch-hole); content must not be obscured by them","iOS: safeAreaInsets.top handles this; Android: displayCutout WindowInsets handles this","Always use system safe area APIs which handle all cutout types; test on devices with cutouts","Assume all screens have full usable area to the top; custom status bar layouts disregarding cutout","Android: WindowInsetsCompat.getInsets(DISPLAY_CUTOUTS); iOS: safeAreaInsets automatic"
@@ -0,0 +1,27 @@
1
+ Pattern Name,Keywords,Pattern Type,When to Use,When to Avoid,iOS Convention,Android Convention,Cross-Platform Note,Accessibility
2
+ Tab Bar,tab bar bottom navigation primary sections,Tab Bar,"Primary app sections (2-5 tabs); always-visible destinations; equal-weight sections","More than 5 tabs; hierarchical content; infrequently used sections","UITabBarController; tabs at bottom; SF Symbols icons; title + icon; max 5 tabs","Bottom Navigation Bar; 3-5 destinations; Material Icons; label visible; min 3 tabs","React Navigation BottomTabNavigator; Flutter BottomNavigationBar / NavigationBar","Each tab must have accessibilityLabel; badge values announced; active tab state announced"
3
+ Stack Navigator,stack push navigation drill-down hierarchy,Stack,"Hierarchical content; drill-down flows; detail views; multi-step flows","Peer-level navigation; equal-weight sections that users switch between frequently","UINavigationController; back button top-left; swipe-right to go back; large title on root","Jetpack Navigation; top app bar with back arrow; system back button/gesture; Material You","React Navigation Stack; Flutter Navigator 2.0 / GoRouter; NavigationStack (SwiftUI)","Back button must be accessible; screen title announced on push; swipe-back has no a11y alternative — add back button"
4
+ Drawer Navigation,drawer sidebar menu hamburger navigation,Drawer,"Secondary navigation; many destinations; settings/profile access; less frequent destinations","Primary navigation (prefer tab bar); if 5+ main sections consider tabs first","Not native iOS — use custom or avoid; prefer tab bar or contextual menus","NavigationDrawer (MD3); hamburger menu in top app bar; swipe from left edge to open","React Navigation Drawer; Flutter Drawer widget; NavigationDrawer in Compose","Drawer must be reachable via button (not gesture only); announce open/close state; focus trapped inside when open"
5
+ Modal Sheet Full-Screen,modal full screen overlay dismiss,Modal,"Complete task before returning; immersive content (camera media); login/auth flows","Non-critical information; simple confirmations; use bottom sheet instead for partial content","UIViewController presented modally; UISheetPresentationController; dismiss via X or swipe down","Full-screen dialog (MD3); dismiss via back button/gesture; optional close icon top-right","React Navigation Modal stack; Flutter showDialog or MaterialPageRoute with fullscreenDialog","Screen reader should announce modal opened; focus moves to modal; background interaction blocked; ESC/back announces dismiss"
6
+ Bottom Sheet,bottom sheet sheet modal partial overlay,Bottom Sheet,"Secondary actions; additional info without leaving context; media player; filter panel","Primary actions (use FAB); single most important action (use button); deep navigation","UISheetPresentationController (.medium .large detents); grab bar; swipe to dismiss","ModalBottomSheet (MD3); persistent or modal; drag handle optional; scrim dismisses","React Native @gorhom/bottom-sheet; Flutter showModalBottomSheet; Compose ModalBottomSheet","Accessible via VoiceOver swipe; announce sheet as 'popup'; focus moves to first interactive element in sheet"
7
+ Search Overlay,search search bar overlay fullscreen,Search Overlay,"App-wide search; filtering large lists; content discovery","Always-visible search bar (embed in nav bar instead); single-screen filtering (use inline)","UISearchController; embedded in nav bar or full-screen; activates on tap; clear button","SearchBar (MD3); expands to full top bar; activated on icon tap; clear X when typing","React Native SearchBar pattern; Flutter SearchDelegate or SliverAppBar pinned search","Search field must be labeled; results count announced; clear button labeled 'Clear search'"
8
+ Deep Link Destination,deep link universal link routing url,Deep Link,"External links (email notifications marketing); re-engagement; cross-app routing","First-time user flow (show onboarding); empty/loading state","Universal Links (apple-app-site-association); scene(_:openURLContexts:); handle in SceneDelegate","App Links (Digital Asset Links JSON); intent-filter in AndroidManifest; handle in Activity","React Navigation linkingOptions; GoRouter uri redirect; useDeepLinking Flutter","Deep links must not bypass required auth; maintain back stack; handle invalid URLs gracefully"
9
+ Split View,split view master detail ipad large screen landscape,Split View,"iPad and large-screen layouts; master-detail patterns; productivity apps","Phone-only apps; content that requires full width; games","UISplitViewController; sidebar + detail column; .doubleColumn or .tripleColumn style","Adaptive layout with NavigationRail + detail pane; fold display support","React Navigation split; Flutter NavigatorRail; adaptive layout pattern","Both panels must be reachable; column headers announced; collapsed/expanded state announced"
10
+ Nested Tab,nested tab tab within tab secondary tabs,Nested Tab,"Section-within-section content; multiple dimensions of categorization","More than 2 levels of tab nesting; when flat alternatives exist; confuses users quickly","Avoid nesting UITabBarController; use segment control inside a tab instead","Top Tabs inside a bottom nav tab via ViewPager2; use sparingly; max 2 levels","React Navigation nested stacks inside bottom tabs; Flutter tabs inside tab","Each level of tabs must be labeled distinctly; avoid duplicate tab labels across levels"
11
+ Top Tab Bar,top tab horizontal scrollable tab swipe,Top Tab Bar,"Peer-level content categories; swipeable between sections (social feeds media)","Primary app navigation (prefer bottom nav on mobile); more than 7 top tabs","Not native iOS — use UISegmentedControl for 2-3 options; TabView with PageTabViewStyle","TabRow / ScrollableTabRow (MD3); swipe between pages; indicator underline","React Native react-native-tab-view; Flutter TabBar + TabBarView","Tab items must be labeled; selected state announced; swipe gesture navigable by accessibility"
12
+ Navigation Rail,navigation rail side rail large screen tablet,Navigation Rail,"Tablet/large phone landscape; 3-7 destinations; when screen width > 600dp","Small phone screens; narrow viewports; more than 7 destinations","Not a native iOS component; use sidebar on iPad (UISplitViewController sidebar)","NavigationRail (MD3); left side on landscape tablet; icons with optional labels","Flutter NavigationRail; Compose NavigationRail; adaptive: bottom nav on phone → rail on tablet","Tab order follows rail items top-to-bottom; FAB in rail header should be first in focus order"
13
+ Swipe Page Navigation,swipe page pager horizontal scroll pages,Swipe Navigation,"Onboarding screens; media galleries; flat peer content (feeds stories)","Navigating hierarchical content; when page count > 7; if back navigation is ambiguous","UIPageViewController; page control dots; scroll indicator; avoid with tab bar overlap","ViewPager2 (MD3); HorizontalPager in Compose; page indicator dots optional","React Navigation tab with swipeEnabled; Flutter PageView; Swipeable (RN Reanimated)","Page change announced; page count communicated; swipe has no keyboard alternative — provide next/prev buttons"
14
+ Settings Navigation,settings preferences drill-down sections,Settings,"App settings and preferences; user profile; account management","Dynamic content; primary features; items users access daily","UITableViewController grouped style; drill-down push nav; toggles + selection cells","Settings screen with grouped list (MD3 List); switch rows; drill-down for sub-sections","React Native SettingsScreen pattern; Flutter ListTile navigation; GoRouter nested routes","Section headers announced; toggle state read aloud; destructive actions require confirmation"
15
+ Contextual Menu Navigation,context menu long press popup quick action,Contextual Navigation,"Quick actions on items (edit delete share); item-level secondary actions","Primary action (use button); navigation to unrelated screens","UIContextMenuInteraction; UIMenu; preview peek; activates on long press","Context menu (MD3); anchor to item; PopupMenu; long press trigger","React Native ContextMenu; Pressable onLongPress; Flutter ContextMenuButtonItem","Accessible via 'Actions' in VoiceOver; menu items announced; dismissed on Escape/back"
16
+ Tab Badge,tab badge notification unread count indicator,Tab Badge,"Unread count; new content notification; pending action count","Decorative use; counts that update excessively; showing counts > 999","UITabBarItem.badgeValue; max 3 digits + '+'; red circle top-right of icon","Badge on Navigation Bar destination; MaterialBadge; optional text badge or dot","React Navigation tabBarBadge; Flutter Badge widget (Material 3)","Badge values announced with tab label: '3 unread, Inbox tab'; badge-only dots say 'new content'"
17
+ Master-Detail,master detail list select,Master-Detail,"Viewing items in a list and their detail; email news reader; contacts","When items have no meaningful detail; single-item apps; dynamic content with no list","UISplitViewController (iPad); collapses to NavigationController on iPhone","Adaptive layout: list + detail pane on large; single pane on phone","Flutter responsive layout NavigationRail + detail; React Navigation split","List items have accessible names; detail pane announced when updated; loading states announced"
18
+ Floating Action Button Navigation,fab floating action button primary action navigate,FAB Navigation,"Launching creation flow (new message new post); single most important action","Showing multiple options (use bottom sheet or menu); navigation between peer sections","Not standard iOS — use large primary button or toolbar button","FAB (MD3); bottom-right position; morphs to small/medium/large","React Native FAB; Flutter FloatingActionButton; Compose FloatingActionButton","FAB must have accessibilityLabel (not just icon); tooltip on long press describes action; single FAB per screen"
19
+ Onboarding Flow Navigation,onboarding wizard step flow multi-step,Onboarding,"First-time user setup; feature discovery; permission request sequence","Returning users who completed onboarding; optional features","PageViewController with progress indicator; 'Get Started' CTA; skip option","Compose onboarding with AnimatedVisibility; step indicator; 'Continue' / 'Skip' actions","React Navigation onboarding stack; Flutter onboarding page flow; stack with no back","Skip button must be accessible; step number announced ('Step 2 of 4'); 'Finish' announces completion"
20
+ Back Navigation iOS,back navigation ios swipe gesture return,Back Navigation (iOS),"Returning to previous screen; navigating up in hierarchy","Exiting modal flows (use dismiss/done); custom transitions that override system gesture","UINavigationController back swipe; 'Back' label with previous screen title; left edge swipe","Not applicable on iOS — Android uses different pattern","React Navigation iOS uses swipe-back by default; cannot fully prevent system gesture","Back button must have accessible label; if custom back hidden — add explicit close/done button"
21
+ Android Back Navigation,back button android system gesture navigation,Back Navigation (Android),"Returning in back stack; Android predictive back gesture (API 34+)","Inconsistent with forward navigation direction; clearing back stack unexpectedly","Not applicable on Android","System back button/gesture; predictive back animation (API34+); onBackPressed override","React Native BackHandler; Flutter Navigator pop; Compose BackHandler","Back gesture is system-level accessible; add software back button if gesture may not be discoverable"
22
+ Expandable List Navigation,expandable list accordion sections expand collapse,Expandable List,"Grouped settings with subcategories; categorized content; FAQs","Deep hierarchical navigation (prefer push nav); if items have detail views (push instead)","DisclosureGroup (SwiftUI); expandable UITableView sections","ExpandableListView; LazyColumn with expand state in Compose","React Native Accordion; Flutter ExpansionTile; AccordionSection","Announce expanded/collapsed state; 'expanded' or 'collapsed' appended to section header"
23
+ Quick Actions Home Screen,quick action home screen shortcut 3d touch long press,Quick Actions,"Common app actions from home screen; power-user shortcuts","Actions requiring authentication; destructive irreversible actions","UIApplicationShortcutItem (Home screen); UIContextMenuInteraction (in-app peek)","Android shortcuts (static + dynamic); App manifest shortcut; pinned shortcuts","React Native (iOS only quickActions); not available in Flutter for Android without native code","Each shortcut must have a title; avoid misleading action names; confirm destructive shortcuts"
24
+ Search Results Navigation,search results list filter navigate,Search Results,"Displaying filtered content; showing search suggestions; navigating to result items","Empty states without messaging; results without back-to-search path","UISearchController resultsController; push result detail on tap; clear returns to search","Search results in RecyclerView; tap to navigate; back returns to search with query preserved","React Native FlatList with search results; Flutter SearchDelegate buildResults","Announce result count; 'No results' announced; result items have descriptive accessible names"
25
+ Tab Switcher,tab switcher browser-like multiple instances,Tab Switcher,"Managing multiple open items (browser tabs); multi-window workflow","Standard single-flow apps; creates cognitive overhead; use sparingly","UITabOverview; Safari-style grid; SwiftUI approach varies","Chrome Custom Tabs; multi-window Android 12+ split-screen","React Native WebView tab pattern; Flutter WebView with tab management","Tab count announced; active tab identified; close tab buttons labeled with tab title"
26
+ Pop-up Menu,popup menu dropdown anchor contextual,Pop-up Menu,"Selecting from 2-6 options anchored to element; sort options; filter options; secondary actions on item","Long lists (use full sheet); primary action (use button); permanent choices","UIMenu (iOS 14+); anchored popover on iPad; action sheet on iPhone","DropdownMenu (MD3) anchored popover; dismisses on outside tap or selection","React Native Modal with styled menu; @react-native-menu/menu; Flutter PopupMenuButton","Menu items announced; checkmarks in menu read as 'selected'; dismiss on Escape/back"
27
+ Share Sheet,share sheet system share native ios android,Share Sheet,"Sharing content to other apps or contacts; exporting data","App-internal sharing (show inline options instead); if only 1 destination","UIActivityViewController; system sheet; cannot customize activity order","Android Sharesheet (Intent.ACTION_SEND); ChooserIntent; recent contacts shown","React Native Share API; Flutter Share plugin; both trigger native system sheet","Native share sheets are fully accessible; custom share UIs must provide same actions with labels"
@@ -0,0 +1,17 @@
1
+ Pattern Name,Keywords,Stage,Purpose,When to Use,Conversion Impact,iOS Convention,Android Convention,Anti-Pattern
2
+ Value-First Onboarding,value first show benefit before ask onboarding start,Pre-signup,Show app value through screenshots or brief interactive demo before asking for account creation,"Apps with strong visual value prop (photos design tools social); apps where sign-up friction is high","High: +25-40% trial activation; users who see value convert at 2-3× rate","Show 3-5 hero screens with clear benefit statements and screenshots; no more than 4 swipe slides","Full-screen ViewPager with illustrated value props; indicator dots; 'Get Started' floating CTA at bottom","Showing value-less generic illustrations (showing phone icons instead of actual app screens)"
3
+ Permission Priming Screen,permission priming rationale camera photos location notification,Permission,Explain WHY permission is needed before system prompt appears to increase grant rate,"Before any system permission dialog: camera photos location notifications contacts","High: +40-60% permission grant rate vs cold system prompt; context dramatically improves trust","Custom screen matching iOS style (white card centered icon title body 'Allow' button 'Not Now' secondary button); then immediately trigger system dialog","Custom rationale screen MD3 style before system dialog; include icon matching permission type","Showing system permission dialog cold without any context; asking for all permissions on first launch"
4
+ Progressive Permission Request,progressive permission contextual request at point of need,Permission,"Request permissions only when user attempts the requiring feature; not on app launch","All permissions that aren't instantly needed (which is most of them)","Medium-High: reduces permission anxiety; natural context = better grant rate","Trigger UIAlertController or custom rationale at the moment of feature tap; back off gracefully if denied","Use shouldShowRequestPermissionRationale() to determine rationale need; contextual request flow","Asking all permissions on first launch before user has context for why they're needed"
5
+ Interactive Tutorial,interactive tutorial coach mark tooltip feature discovery,Tutorial,"Guide user through core interactions by having them perform them within real UI (not sandbox)","Feature-rich apps where key interactions are non-obvious; first 3-5 sessions","Medium: +20% D7 retention for apps with meaningful interactive tutorial vs video-only","UICoachMark style tooltip with arrow; dim background; single focused step; 'Got it' dismiss; progress indicator","Spotlight highlight with dimmed overlay; MD3 typography for tooltip; gesture indicator animation","Long tutorial before user can use app; skippable tutorial that hides critical info not shown elsewhere"
6
+ Skip-to-Value,skip option bypass onboarding trial,Pre-signup,Allow users to explore app before committing to account creation,"Any app where core value is demonstrable without account: note-taking productivity reading","Medium: captures users who reject sign-up walls; convert to registered later after value delivery","'Skip' / 'Explore first' secondary button visible below primary CTA on all onboarding screens","Floating skip button top-right; low visual weight (text only no border); stores state to re-prompt later","Hiding skip so well users can't find it; asking for account immediately after 'Skip' when entering first feature"
7
+ Empty State First Use,empty state first use zero state,Tutorial,"Onboarding screen embedded in the app when no data exists yet; shows what the screen will look like + how to populate","Any screen that starts empty: tasks habits bookmarks collections","Medium: +15-25% activation; empty state with CTA drives first data creation","Illustration (SF Symbols or custom) + headline + body + large CTA button; .frame(maxWidth: 280) centered","Empty state with Material illustration + 'Get Started' extended FAB or CTA button; centered layout","Generic 'No items found' text with no illustration or CTA; showing error icon instead of encouraging illustration"
8
+ Social Proof Onboarding Screen,social proof rating reviews users count testimonial,Pre-signup,"Show credibility signals (rating downloads user count testimonials) early in onboarding to build trust","Free apps competing in crowded categories; apps where trust is key (health finance)","Medium: +10-20% signup completion; particularly effective for cold audience (paid traffic)","App Store rating badge (4.8★); user count '100K+ users'; centered layout; before signup CTA","Similar but use Google Play rating; 5-star visual indicator; horizontal review cards scrollable","Fake or unverifiable social proof; reviews without attribution; showing inflated stats that damage trust later"
9
+ Account Creation Late,late registration defer signup,Pre-signup,"Defer mandatory account creation until after user has experienced app value or created content","Apps where user generates data before needing sync: journaling notes fitness tracking","High: +30-50% completion vs upfront signup; user has more motivation after creating content","Guest mode → 'Save your progress' prompt after first content creation → native signup (Sign in with Apple primary)","Google Sign-In as primary; email secondary; progress loss warning before first close","Requiring account on first launch before any value; showing signup after 30 seconds of app open with no engagement"
10
+ Sign in with Apple,sign in apple social auth login quick,Permission,Streamline authentication with one-tap Sign In with Apple on iOS reducing friction,"All iOS apps with account creation — required by Apple if any third-party social login offered","High: +40% signup completion vs email form; users trust Apple auth and share less data","Required if other social logins exist; Apple button must be at same prominence as other social buttons; follow HIG button styling","Optional on Android since not native; use Google Sign-In as Android equivalent","Violating Apple's requirement to offer Sign in with Apple alongside other social options (App Store rejection risk)"
11
+ Paywall on Day 3-7,paywall timing delay freemium trial premium,Paywall,"Show paywall after user has experienced value over multiple sessions; not on first launch","Subscription apps with trials; after user completes key 'aha moment' actions","High: Best performing paywall timing is after 3rd+ session or after key value delivery","UIViewController presented as sheet; trial offer prominently shown; 'Start Free Trial' primary; 'Maybe later' secondary visible","BottomSheetDialog or full-screen Activity; trial duration in prominent font; feature list with checkmarks; Google Play billing","Showing paywall on first open or after only 30 seconds; hiding 'No thanks' / 'Maybe later' CTA"
12
+ Feature Spotlight (Coach Mark),coach mark spotlight tip bubble overlay,Tutorial,"Highlight a single new or non-obvious feature with a focused tooltip overlay","New feature launches; power features that provide value but require discovery","Medium: +15% feature adoption for featured capability","UICoachMark style: semi-transparent dark overlay with highlighted cutout; tooltip bubble; tap anywhere to dismiss","Spotlight with MotionLayout animation; MD3-styled tooltip; single step preferred; part of a sequence","More than 5-7 coach marks in sequence; coach marks on every launch; auto-advancing coach marks too fast"
13
+ Biometric Setup Prompt,biometric face id touch id fingerprint login setup,Permission,"Prompt to enable biometric authentication (Face ID/Fingerprint) for secure quick login","After account creation or first successful password login; apps with sensitive data","Medium-High: biometric enables users to stay logged in increasing retention","LocalAuthentication framework; NSFaceIDUsageDescription; system prompt; custom pre-prompt explaining convenience","BiometricPrompt API; prompt after PIN setup; 'Use fingerprint to log in faster'","Forcing biometric without password fallback; prompting for biometric before user has created account"
14
+ Notification Permission (Contextual),notification prompt contextual timing push permission,Permission,"Request notification permission at moment user would clearly benefit from notifications","After key user action that creates notification-eligible content: task created appointment set order placed","High: contextual request = +50-80% grant vs launch request; user understands benefit","Custom rationale card + system prompt; 'Stay updated on [specific thing user just did]' copy","Custom rationale + system dialog (Android 13+); show specific example notification","Requesting notifications on first screen with generic 'Enable notifications for the best experience' copy"
15
+ Skeleton Loading on First Load,skeleton loading placeholder first load appears,Tutorial,"Show skeleton/shimmer placeholder UI that matches expected content shape during initial data load","Any screen with network-fetched content; better UX perception than blank screen or spinner for >300ms load","Medium: improves perceived performance; users who see skeleton complete first-time flows at higher rate","Gray gradient shimmer matching content row shapes; 200ms delay before showing (avoid flash for fast loads)","Shimmer animation matching MaterialCardView shapes; fade-in when real content loads","Generic spinner in center of screen; showing 'Loading...' text without skeleton; skeleton shape not matching real content"
16
+ Onboarding Quiz / Personalization,onboarding quiz personalization questions customize experience,Pre-signup,"Ask 2-4 questions to personalize initial experience and increase engagement; users feel product is made for them","Health fitness learning finance apps where personalization meaningfully changes content","Medium-High: +20-35% D30 retention for apps with meaningful personalization vs generic start","Simple card-style questions; progress bar; visual answer options (icons + text); max 4 questions; skip option on each","MD3 RadioButton or Card selection; full-width answer cards; visible step indicator","10+ question quiz; forcing answers without skip; using quiz purely for marketing data without actual personalization"
17
+ Google Sign-In,google sign in social auth android login,Permission,One-tap Google Sign-In for quick Android authentication reducing form friction,"Android apps with account creation — Google Sign-In is equivalent of Sign in with Apple for Android","High: +35% Android signup completion vs email form; pre-filled with Gmail info","Google Sign-In available on iOS (GIDSignIn SDK) but lower priority behind Apple; show below Sign in with Apple","Google Identity Services (GIS) / Credential Manager API; one-tap sign in; Google button follows brand guidelines","Using deprecated GoogleApiClient; custom Google button that doesn't match brand guidelines"
@@ -0,0 +1,22 @@
1
+ Topic,Keywords,iOS Convention,Android Convention,Cross-Platform Recommendation,When to Deviate
2
+ Back Navigation,back navigation gesture button return previous screen,"Swipe right from left edge of screen (UINavigationController interactivePopGestureRecognizer); back button in top-left of navigation bar with previous screen title; no visible hardware button","System back button (hardware or gesture) on left edge or bottom; Predictive Back (Android 13+ API 33) shows destination preview; NavigationBar back button","Always support platform-native back: iOS swipe-back + back button; Android system back + up button in top app bar; never remove default back without custom alternative","Never deviate from back navigation — it is the most fundamental navigation pattern; custom navigation structures must still support system back"
3
+ Typography Scale,typography scale font size text size hierarchy,SF Pro typeface; Dynamic Type sizes: caption2=11pt to largeTitle=34pt; 6 standard sizes; Title 28pt Body 17pt Caption 12pt,Roboto typeface; Material Type Scale: displayLarge=57sp to labelSmall=11sp; title categories body categories label categories using sp units,"Use platform fonts (SF Pro iOS / Roboto Android) or brand font while keeping system size scales and accessibility; never hard-code absolute pt/dp sizes — use text styles","Brand font acceptable on both platforms if it matches x-height and weight of system font; always maintain Dynamic Type / font scale support regardless of brand font"
4
+ Color System — System Colors,system colors semantic colors adaptive,UIColor.systemBlue / systemRed / etc.; automatic dark/light mode adaptation; semantic colors (UIColor.label UIColor.background); do not use static RGB for text/background,Material Color Roles (primary onPrimary primaryContainer surface onSurface etc.); auto dark/light from ColorScheme; dynamicColor API Android 12+ (user wallpaper-based colors),"Use semantic/role-based colors not static hex for foreground/background; define light+dark variants for all custom colors; test in both system appearances","Custom brand palette OK — but must define dark mode variants; never use static white/black for text (use semantic label colors)"
5
+ Dark Mode,dark mode night mode system appearance adaptive,"traitCollectionDidChange / UIUserInterfaceStyle; named Color assets with both appearances; SwiftUI Color(.systemBackground) adapts automatically; systemMaterials for blur layers","Force dark / Force light via Application.setDefaultNightMode; MaterialTheme darkColorScheme/lightColorScheme in Compose; dynamicDarkColorScheme (Android 12+)","Support both light and dark and follow system setting by default; use semantic colors and avoid hardcoded colors; test on OLED displays where true black matters","Can lock to one appearance (dark-only apps dark reader apps) if intentional brand decision — must be explicit in onboarding and settings"
6
+ Icons — System vs Custom,icon sf symbols material icons system library,SF Symbols: 6000+ icons; weight/scale matches text weight; colored symbols in iOS 16+; symbol effects in iOS 17+; free with Apple developer account,Material Symbols / Material Icons: 2500+ icons; filled/outlined/rounded/sharp styles; Adaptive icon for app icon; dynamic color tinting via colorFilter,"Use platform icon libraries for generic actions (back search close share settings delete); custom icons for brand-specific or unique actions; maintain 1:1 icon meaning across platforms","Brand icons always custom; use platform icons for familiar actions to reduce cognitive load (save = floppy disk is universal)"
7
+ FAB and Primary Action,fab floating action button primary cta action,No native FAB — use large primary button in bottom toolbar; UIButton prominentFillButtonStyle; or custom circular button bottom-right,"FAB (Material 3): bottom-right primary action; Small/Medium/Large/Extended FAB; morphs to extended on interaction; use FAB for ONE primary screen action","iOS: bottom center or bottom-right primary button; Android: FAB bottom-right; both: single primary action per screen; secondary actions in sheet or top bar","OK to use FAB-style on iOS for very action-heavy apps (productivity creation tools); must include label if action is unclear from icon alone"
8
+ Haptic Feedback,haptic taptic engine feedback vibration response,UIImpactFeedbackGenerator: .light .medium .heavy .rigid .soft; UISelectionFeedbackGenerator for pickers; UINotificationFeedbackGenerator: .success .warning .error,"HapticFeedback: VIRTUAL_KEY KEYBOARD_PRESS CLOCK_TICK LONG_PRESS; VibratorManager (API 31) amplitude control; many low-end Android devices have weak or no haptic engines","iOS: add haptics to key interactions (selections toggles success errors pulls); Android: use sparingly as hardware varies; always pair with visual + audio feedback","Reduce haptics if user motion/haptic settings indicate sensitivity; never haptic-only feedback"
9
+ Status Bar Style,status bar appearance style color light dark,preferredStatusBarStyle: .lightContent / .darkContent; setNeedsStatusBarAppearanceUpdate; hidden for immersive full-screen (statusBarHidden); UIStatusBarStyle auto with dark mode,"WindowInsetsController.setSystemBarsAppearance(APPEARANCE_LIGHT_STATUS_BARS) or dark; statusBarColor deprecated API 30+; edge-to-edge WindowCompat.setDecorFitsSystemWindows(false)","Match status bar content color (icons/clock) to background: light background → dark icons; dark background → light icons; test in both appearances","Hide status bar only for true immersive experiences (video games photo viewers); do not hide for normal content apps"
10
+ Alert and Dialog Style,alert dialog confirm destructive warning popup,UIAlertController(.alert): centered popup with title message up to 3 buttons; two-button layout side-by-side; destructive = red button on left; cancel most prominent right,AlertDialog (MD3): centered card with title body and 2 buttons; text buttons not raised; confirm right side; negative left; destructive confirm uses primary color not red,"iOS: use UIAlertController pattern (title + message + max 2-3 actions); Android: use AlertDialog/BasicDialog pattern; both: clear action labels not 'OK/Cancel'","Both platforms accept custom styled dialogs as long as they follow the core pattern: modal focus trap, backdrop dimming, keyboard dismissible"
11
+ App Icon,app icon home screen design shape rounded corner,Rounded rectangle (automatic by system); 1024×1024px no transparency; iOS clips to rounded rect; no background required; SF Symbols only inside app not for icon,Adaptive icon: foreground + background layers; 108×108dp canvas; 72dp safe zone; playful with parallax; dynamic color (Android 13+) for themed icons,"Design for both platforms: single icon on iOS (one cornerRadius) multiple adaptive layers on Android; test icon on various wallpapers; reserve bottom-third of canvas for foreground","Unique icon shapes/backgrounds intentional for brand recognition; avoid text in icon (poorly visible at small sizes)"
12
+ Scroll Behavior,scroll momentum bounce overscroll indicator,UIScrollView bounce: rubber-band stretch beyond edges (satisfying iOS feel); contentInset for keyboard and bars; scrollsToTop on status bar tap,Overscroll glow / stretch (MD3 default): edge effect when hitting scroll bounds; setOverScrollMode NEVER to disable; no rubber-band by default,"iOS: rubber-band bounce is expected — never disable without strong reason; Android: overscroll indicator is subtle — acceptable to keep default","Disable bounce only in specific UI contexts (maps full-screen canvas) — users expect it on lists"
13
+ Notification Permissions,notification permission push local alert,System prompt: one-time permission request (iOS 13+); earlier = after value delivery not on launch; single attempt — must re-request via Settings if denied,Runtime permissions (Android 13+ TIRAMISU) for POST_NOTIFICATIONS; earlier Android auto-granted; can show rationale dialog before request,"Show permission rationale screen before system prompt on both platforms; ask after user has experienced value; provide fallback if denied; detect denied vs not-asked","Ask on first launch only if notifications are core to app value; otherwise ask contextually when user initiates notification-relevant feature"
14
+ Share Sheet (System),share sheet share content actionsheet native,UIActivityViewController: pass items (text URL image); excludedActivityTypes for specific exclusions; automatically handles social email copy save,Android Sharesheet (Intent.ACTION_SEND): pass MIME type and content URI (not file path); Intent.createChooser for title; share target API for contacts row,"Both: use system share sheet — do not build custom because system handles app discovery, receiving app handles formatting","Custom share only if sharing to app-specific destinations (e.g., chat app shares within own threads)"
15
+ Permissions Flow,permissions flow runtime permission camera photos location,One-time permission prompt (cannot re-prompt if denied); NSUsageDescription in Info.plist required; Privacy manifest (iOS 17+) for API access,"Runtime permissions at point of use (not on launch); shouldShowRequestPermissionRationale(); open Settings if denied; group related permissions","Prime user before system prompt; contextually request at moment of use; handle denied gracefully (show in-app Settings link); never gate core app value on optional permissions","Some apps (security cameras parental control) require upfront permissions — explain clearly in onboarding why"
16
+ Long Press Context Menu,long press context menu peek preview actions,UIContextMenuInteraction (iOS 13+); UIPreviewParameters for shape; UIContextMenuConfiguration; preview + menu actions; hierarchical actions with submenu,View.setOnCreateContextMenuListener; registerForContextMenu; ContextMenu.Menu API; popup menu alternative; PopupMenu anchored to view,"Use long press for secondary contextual actions; keep to 5-7 items; include icons; group with separators; destructive action last (red on iOS)","Never make long press the ONLY discovery path for important actions — surface frequently needed actions in visible UI"
17
+ Keyboard Types,keyboard type input mode number email phone url,keyboardType: .default .emailAddress .numberPad .phonePad .URL .decimalPad .twitter .webSearch; returnKeyType: .done .send .next .search,inputType: text textEmailAddress number phone textUri; imeOptions: actionDone actionSend actionNext actionSearch; singleLine/multiline,"Set appropriate keyboard type for each input field; set returnKey/imeOptions to match expected action; test tabbing through forms","Always override default keyboard for specialized inputs (email phone number) — users expect correct keyboard automatically"
18
+ Swipe Refresh Pattern,pull down refresh reload user-triggered,UIRefreshControl tintColor attribution; must attach to UIScrollView subclass; spinner + optional title; auto end on data arrive,SwipeRefreshLayout wraps RecyclerView; setOnRefreshListener; setRefreshing(false) when done; MD3 use PullRefresh Compose,"Both: refresh UI must be attached to topmost scroll view; trigger actual data fetch not just UI spin; end refresh indicator after data loaded","Always add a manual refresh button alternative for accessibility alongside pull-to-refresh gesture"
19
+ Safe Area Colors,safe area color background edge extend,UIColor extending below safe area: set backgroundColor on UIViewController.view or UIScrollView contentView; background shows behind home indicator,"systemGestureExclusionRects for immersive; window background extends behind nav bar and gesture area; edge-to-edge recommended","Extend background color into safe areas (behind home indicator / nav bar) so content doesn't feel cut off; only interactive content respects safe area insets","For media apps (video photo) extend content edge-to-edge and let safe areas be clear/transparent"
20
+ Fonts — Dynamic Type,dynamic type font size accessibility scale user preference,"UIFont.preferredFont(forTextStyle:); responds to user's font size preference (Extra Small to Accessibility Extra Extra Extra Large); .adjustsFontForContentSizeCategory=true always","sp units automatically scale with font size preference (0.75sp-1.3sp range common); autoSizeTextTypeUniformly for scaling within bounds","Always use Dynamic Type / sp scaling; test at largest accessibility text size (300% scale); layouts must accommodate large text","Never disable Dynamic Type / font scaling; layouts that break at 200% font size are accessibility failures"
21
+ Predictive Back Android,predictive back android gesture api 34,Not applicable on iOS,Predictive back: android:enableOnBackInvokedCallback=true in manifest; onBackPressedCallback API; custom back animation via OnBackAnimationCallback (API 34+),"React Native v0.76+ predictive back support; Flutter adds support in upcoming releases; enables swipe-from-edge preview of back destination","Must implement for target API 34+; improves gesture discoverability on Android 13+ devices"
22
+ Tablet Breakpoints,tablet responsive breakpoint medium large,Compact (<375pt): single column; Regular (iPad 768pt+): 2+ columns; use UISplitViewController for M+L; size classes via UITraitCollection,"Compact (<600dp): single pane; Medium (600-840dp): 2-pane rail+content; Expanded (840dp+): 3-pane or sidebar+detail; WindowSizeClass in Compose","Use window size classes to adapt layouts at 3 breakpoints; NavigationRail at medium; NavigationDrawer or permanent sidebar at expanded","App-specific breakpoints OK (e.g., 500dp instead of 600dp) — but must test across range of real devices"
@@ -0,0 +1,19 @@
1
+ Category,Guideline,Description,Do,Don't,Code Good,Code Bad,Severity,Docs URL
2
+ Performance,Use ListView.builder for long lists,Column with children list computes all items upfront; ListView.builder uses lazy rendering building only visible items plus a small buffer,"Use ListView.builder with itemCount and itemBuilder; set itemExtent if all items same height for maximum performance; cacheExtent for look-ahead","Wrap long lists in SingleChildScrollView + Column (OOM risk with hundreds of items)","ListView.builder(itemCount: items.length, itemBuilder: (ctx, i) => ItemRow(item: items[i]), itemExtent: 72)","Column(children: items.map((i) => ItemRow(item: i)).toList()) // All items built at once",Critical,https://api.flutter.dev/flutter/widgets/ListView/ListView.builder.html
3
+ Performance,Use const constructors to prevent unnecessary rebuilds,Widgets without const rebuild even if their props haven't changed; const widgets are compile-time constants and never rebuilt,"Add const to all widgets possible: const Text() const Icon() const SizedBox() const Padding(); use const everywhere in widget trees","Build widget trees without const; create new Color/TextStyle instances in build() without const","Column(children: [const Text('Hello'), const Icon(Icons.star), const SizedBox(height: 16)])","Column(children: [Text('Hello'), Icon(Icons.star), SizedBox(height: 16)]) // Rebuilt on every parent rebuild",High,https://dart.dev/language/const#constant-constructors
4
+ Performance,Minimize build() method work,Everything in build() runs on every rebuild triggered by setState or parent rebuild; expensive operations slow frames,"Move expensive computations outside build(); use cached_network_image for images; define static data as class constants; use RepaintBoundary to isolate subtrees","Parse JSON/dates in build(); make network calls in build(); create complex data structures in build()","class _MyState extends State<My> { late final sorted = items.sorted(); @override Widget build(ctx) => ListView.builder(itemCount: sorted.length) }","Widget build(ctx) => ListView.builder(itemCount: items.sorted().length) // sorted() runs every frame",High,https://docs.flutter.dev/perf/best-practices
5
+ Navigation,Use GoRouter for type-safe declarative routing,"Navigator 1.0 push/pop is imperative and doesn't support deep links/web well; Navigator 2.0 is complex; GoRouter provides declarative URL-based routing with type-safety","Define routes in GoRouter with path patterns; use go() not push() for replacement; goNamed() for type-safe navigation; ShellRoute for persistent bottom nav","Use Navigator.push() for deep-link-compatible screens; use route names as plain strings","final router = GoRouter(routes: [GoRoute(path:'/home', builder:(ctx,state)=>HomeScreen()), GoRoute(path:'/user/:id', builder:(ctx,state)=>UserScreen(id:state.pathParameters['id']!))])","Navigator.push(context, MaterialPageRoute(builder:(_)=>HomeScreen())) // No deep link support",High,https://pub.dev/packages/go_router
6
+ Navigation,Configure bottom tab persistence with StatefulShellRoute,Simple BottomNavigationBar with Navigator loses stack state when switching tabs; StatefulShellRoute preserves each branch's navigation stack,"Use StatefulShellRoute.indexedStack() in GoRouter; each branch gets its own Navigator; state preserved on tab switch","Replace tabs by popping all routes on switch; use separate NavigatorKeys manually without GoRouter","StatefulShellRoute.indexedStack(builder:(ctx,state,shell)=>ScaffoldWithNavBar(shell:shell), branches:[StatefulShellBranch(routes:[GoRoute(path:'/home',...)])])","BottomNavigationBar(onTap:(i)=>setState(()=>_index=i)) // Loses stack state on tab switch",High,https://pub.dev/documentation/go_router/latest/go_router/StatefulShellRoute-class.html
7
+ Layout,Use SafeArea widget for notch-safe layouts,Widgets directly in Scaffold body without SafeArea can render behind notch status bar or home indicator,"Wrap content in SafeArea; Scaffold already handles top nav bar area but body content needs SafeArea for edge cases; pass minimum parameter for partial areas","Hardcode top padding; use MediaQuery.of(ctx).padding.top directly without SafeArea widget","Scaffold(body: SafeArea(child: Column(children: [YourContent()])))","Scaffold(body: Column(children: [Padding(padding: EdgeInsets.only(top: 44), child: YourContent())])) // Hardcoded",High,https://api.flutter.dev/flutter/widgets/SafeArea-class.html
8
+ Layout,Use MediaQuery and LayoutBuilder for responsive layouts,Hardcoded dimensions break on different screen sizes; responsive layouts adapt to available space,"Use MediaQuery.sizeOf(context) for screen dimensions; LayoutBuilder for parent-constrained sizing; avoid accessing in build root (use Slivers instead)","Hardcode pixel width for phone (assumes same screen); use MediaQuery deep in widget tree frequently (causes rebuild cascade)","LayoutBuilder(builder:(ctx,constraints)=>constraints.maxWidth>600?WideLayout():NarrowLayout())","Container(width: 375) // Breaks on any other screen size",High,https://api.flutter.dev/flutter/widgets/LayoutBuilder-class.html
9
+ Layout,Scaffold provides correct layout structure,Building custom scaffold-like structures loses MaterialApp integration (Drawer BottomSheet Snackbar FAB positioning) and visual regression risks,"Use Scaffold for every screen; use Scaffold's body bottomNavigationBar floatingActionButton drawer appBar properties; nest Scaffolds only for specific cases","Create custom Stack-based layouts to replicate Scaffold behavior; use root-level Stack for FAB and bottom bar","Scaffold(appBar: AppBar(title: Text('Home')), body: HomeContent(), bottomNavigationBar: NavBar(), floatingActionButton: FAB())","Stack(children:[HomeContent(), Positioned(bottom:16,right:16,child:FAB()), Positioned(bottom:0,...NavBar())]) // Wrong",Critical,https://api.flutter.dev/flutter/material/Scaffold-class.html
10
+ State Management,Use Riverpod for scalable state management,StatefulWidget setState works for local state but global/shared state requires proper DI; Provider is deprecated in favor of Riverpod,"Use Riverpod: StateNotifierProvider for mutable state; FutureProvider for async; ref.watch in build; ref.read in callbacks","Use setState for data shared across screens; use Provider package (deprecated); global variables for state","@riverpod class CounterNotifier extends _$CounterNotifier { @override int build() => 0; void increment() => state++; } // Widget: ref.watch(counterNotifierProvider)","class _State extends State<Widget> { int counter = 0; void inc() => setState(()=>counter++); } // Not scalable for shared state",High,https://riverpod.dev
11
+ Accessibility,Use Semantics widget to provide accessible labels,Many custom widgets have no semantic meaning by default; users of TalkBack and screen readers cannot understand the interface,"Wrap custom interactive widgets in Semantics; use semanticsLabel for Images; excludeFromSemantics for decorative elements; mergeAllDescendantsIntoTree for grouped items","Ignore Semantics for custom widgets; use Icon without semanticLabel; forget to mark headings","Semantics(label: 'Profile photo of ${user.name}', image: true, child: CircleAvatar(backgroundImage: NetworkImage(user.avatarUrl)))","CircleAvatar(backgroundImage: NetworkImage(user.avatarUrl)) // No accessible name",Critical,https://api.flutter.dev/flutter/widgets/Semantics-class.html
12
+ Accessibility,Support font scaling with sp-equivalent sizing,Flutter Text uses logical pixels by default; users who increase system font size in Android/iOS settings see no change,"Use MediaQuery.textScalerOf or textScaleFactor in views; do not use textScaleFactor:1.0 to force disable; allow text to grow","Disable text scaling globally with textScaleFactor:1.0; clamp at small scale; overflow text at large scale using fixed containers","Text('Hello', style: TextStyle(fontSize: 16)) // font scales automatically in Flutter by default — just dont disable it","Text('Hello', textScaleFactor: 1.0, style: TextStyle(fontSize: 16)) // Disables user font size preference",Critical,https://api.flutter.dev/flutter/widgets/MediaQueryData/textScaler.html
13
+ Images,Use cached_network_image for network images,NetworkImage and Image.network don't cache to disk; same URL re-downloads on every screen visit causing slow UX and excess bandwidth,"Use CachedNetworkImage; include placeholder and errorWidget; use cacheKey for URL params that change but image doesn't","Use Image.network for any image that may appear more than once; fetch same URLs repeatedly without cache","CachedNetworkImage(imageUrl: url, placeholder: (ctx,url)=>Shimmer(), errorWidget: (ctx,url,err)=>Icon(Icons.error), fit: BoxFit.cover)","Image.network(url, fit: BoxFit.cover) // No caching, re-downloads every time",High,https://pub.dev/packages/cached_network_image
14
+ Animation,Use Hero widget for shared element transitions,Hero provides automatic shared element transition between routes for a specific tagged widget making transitions feel native and connected,"Add Hero widget with same tag string to same element on both source and destination screens; tag must be unique per screen","Use Hero with non-unique tags (shows debug error); Hero on lists with all items same tag","// Source screen: Hero(tag: 'product-${item.id}', child: Image(url)); // Destination: Hero(tag: 'product-${item.id}', child: LargeImage(url))","Hero(tag: 'product', child: Image(url)) // Non-unique tag — breaks when multiple items on screen",High,https://docs.flutter.dev/ui/animations/hero-animations
15
+ Animation,Use AnimatedWidget and AnimationController correctly,Animation setup with AnimationController requires dispose() to prevent memory leaks; AnimatedBuilder rebuilds less than setState,"Use SingleTickerProviderStateMixin; dispose controller in dispose(); use AnimatedBuilder to limit rebuilds to animated subtree","Forget to dispose AnimationController (memory leak); call setState on every animation tick (rebuilds entire tree)","class _MyState extends State<My> with SingleTickerProviderStateMixin { late final _ctrl = AnimationController(vsync:this, duration:300.ms); @override void dispose() { _ctrl.dispose(); super.dispose(); } }","class _MyState extends State<My> { final ctrl = AnimationController(duration:300.ms); } // No vsync no dispose",Critical,https://api.flutter.dev/flutter/animation/AnimationController-class.html
16
+ Images,Handle image loading states and errors,Images that fail to load or take time show empty/broken UI; no placeholder = layout shift on load,"Always provide placeholder and error widgets; use FadeInImage for smooth appearance; handle loading shimmer","Hope images always load instantly; skip errorWidget; use Image without placeholder causing layout shift","FadeInImage(placeholder: MemoryImage(kTransparentImage), image: NetworkImage(url), fit: BoxFit.cover, fadeInDuration: 200.ms)","Image.network(url) // No placeholder, no error, layout shift on load",High,https://pub.dev/packages/transparent_image
17
+ Platform,Use Platform.isIOS and Platform.isAndroid for platform logic,UI patterns differ between iOS and Android; platform checks allow delivering native-appropriate experience,"Use Platform.isIOS in dart:io for runtime; use defaultTargetPlatform for widget-level; use Theme.of() to access Material/Cupertino theme","Force iOS visual style on Android or vice versa; use .platform == 'ios' string comparison","import 'dart:io'; if (Platform.isIOS) { showCupertinoDialog(...); } else { showDialog(...); }","if (Theme.of(context).platform.toString() == 'TargetPlatform.iOS') // String comparison fragile",Medium,https://api.flutter.dev/flutter/foundation/defaultTargetPlatform.html
18
+ Testing,Use Flutter widget testing for UI verification,Integration tests are slow and flaky; widget tests run in memory and verify widget tree behavior without device,"Use WidgetTester.pumpWidget() pump() pumpAndSettle(); find by semantics label (find.bySemanticsLabel) or type; test user interactions with tester.tap()","Only test business logic ignoring UI; use only integration tests; test by index (find.at(0)) which breaks on reorder","testWidgets('shows user name', (tester) async { await tester.pumpWidget(app); await tester.pump(); expect(find.bySemanticsLabel('Alice'), findsOneWidget); })","testWidgets('test', (t) async { await t.pumpWidget(app); expect(find.byType(Text).at(0), findsOneWidget); }) // Fragile index-based",High,https://docs.flutter.dev/testing/overview
19
+ Error Handling,Use AsyncValue in Riverpod for loading/error states,FutureProvider returns raw Future without loading and error states; AsyncValue provides all three states in one pattern,"Use FutureProvider; handle AsyncValue.when(data:,loading:,error:) in UI; never assume data is ready without check","Access .value directly on AsyncValue without null check; show nothing for loading state","ref.watch(postsProvider).when(data:(posts)=>PostList(posts:posts), loading:()=>const CircularProgressIndicator(), error:(err,stack)=>ErrorWidget(err))","final posts = ref.watch(postsProvider).value! // Throws if loading or error",High,https://riverpod.dev/docs/essentials/side_effects
@@ -0,0 +1,18 @@
1
+ Category,Guideline,Description,Do,Don't,Code Good,Code Bad,Severity,Docs URL
2
+ Performance,Use LazyColumn/LazyRow for long lists,Column with all items renders everything immediately; LazyColumn recycles and renders only visible items with minimal overhead,"Use LazyColumn with items() or itemsIndexed(); provide key lambda for stable identity; avoid heavy composables as direct children","Use Column(content={ items.forEach{item->ItemRow(it)} }) for long lists; repeat items without key identity","LazyColumn { items(items = posts, key = { it.id }) { post -> PostCard(post = post) } }","Column { posts.forEach { post -> PostCard(post = post) } } // All items composed at once OOM risk",Critical,https://developer.android.com/jetpack/compose/lists
3
+ Performance,Minimize recomposition with remember and derivedStateOf,Composables recompose when read state changes; without derivedStateOf computed values trigger recomposition even when output hasn't changed,"Use remember for initialization; derivedStateOf for computed values from state; rememberSaveable for survive-recreation values","Create new object instances in composable without remember; use state.value directly without derivedStateOf when derived value is same","val isScrolled by remember { derivedStateOf { listState.firstVisibleItemIndex > 0 } } // Only recomposes when scrolled changes","val isScrolled = listState.firstVisibleItemIndex > 0 // Recomposes every scroll event",High,https://developer.android.com/jetpack/compose/performance/stability
4
+ Performance,Use stable types and @Stable/@Immutable annotations,Compose uses type stability to decide if recomposition is needed; unstable types (List Map interface) trigger unnecessary recompositions,"Use data classes for UI state; wrap unstable collections in @Immutable; use ImmutableList from kotlinx.collections.immutable","Pass raw List<T> directly as composable parameter (unstable); use non-data class with var fields as state","@Immutable data class UiState(val posts: ImmutableList<Post>, val isLoading: Boolean)","data class UiState(val posts: List<Post>, val isLoading: Boolean) // List is unstable triggers full recomposition",High,https://developer.android.com/jetpack/compose/performance/stability#fix-unstable-collections
5
+ Navigation,Use Navigation Compose with type-safe routes (Compose 1.8+ / NavController),Manual route string matching is error-prone; type-safe routes using @Serializable data classes prevent typos and provide compile-time safety,"Use NavController with type-safe NavDestination (@Serializable objects/classes); NavGraphBuilder DSL; popUpTo for correct back stack","Navigate by raw string 'home/{userId}' with manual parsing; use deprecated FragmentManager with Compose","@Serializable data class Profile(val userId: String); navController.navigate(Profile(userId=id)); composable<Profile> { back -> val args = back.toRoute<Profile>(); ProfileScreen(args.userId) }","navController.navigate(\"profile/$userId\"); composable(\"profile/{userId}\") { back -> back.arguments?.getString(\"userId\") }",High,https://developer.android.com/guide/navigation/design/type-safety
6
+ Navigation,Handle Android back with BackHandler,Compose screens need to intercept system back press for custom behavior; without BackHandler system back navigates out of scope,"Use BackHandler(enabled=condition) composable; disableDefault with enabled=false when not needed; prefer system back behavior when possible","Override Activity.onBackPressed instead of BackHandler in Compose; always enable BackHandler blocking all navigation (memory leak)","BackHandler(enabled = isSearchActive) { isSearchActive = false } // Only intercepts when search is open","// In Activity: override fun onBackPressed() { /* custom */ } // Doesn't work with Compose navigation",High,https://developer.android.com/jetpack/compose/handling-ui-events#back-nav
7
+ Layout,Use WindowInsets for edge-to-edge layouts,"Compose edge-to-edge requires consuming WindowInsets for nav bar status bar; Scaffold handles most cases but custom layouts need explicit inset handling","Call WindowCompat.setDecorFitsSystemWindows(window,false) in Activity; use Modifier.windowInsetsPadding(WindowInsets.systemBars) for custom layouts; Scaffold handles this automatically","Hardcode padding for navigation bar height; ignore gesture navigation bar inset (zero on gesture nav but not on 3-button)","@Composable fun Screen() { Modifier.windowInsetsPadding(WindowInsets.navigationBars) } // Manual edge-to-edge","Modifier.padding(bottom = 48.dp) // Hardcoded nav bar height breaks on gesture navigation",Critical,https://developer.android.com/develop/ui/compose/layouts/insets
8
+ State,Lift state appropriately — hoist to lowest common ancestor,State defined inside a composable can't be shared with siblings or parents needing it; unhoisted state prevents reuse and testing,"Hoist state to nearest common ancestor; pass state down and events (lambdas) up; use ViewModel for screen-level state","Class-level state in pure composable functions; duplicate state in sibling composables instead of hoisting","@Composable fun Screen(viewModel: ScreenViewModel = hiltViewModel()) { val uiState by viewModel.uiState.collectAsState(); Content(state=uiState, onAction=viewModel::handle) }","@Composable fun Screen() { var isLoading by remember { mutableStateOf(false) }; SiblingA(isLoading); SiblingB(isLoading) } // Duplicated",High,https://developer.android.com/jetpack/compose/state#state-hoisting
9
+ State,Use ViewModel with StateFlow for screen state,Compose recomposition handles UI updates but state must survive configuration changes; ViewModel + StateFlow provides lifecycle-aware reactable state,"Use StateFlow<UiState> in ViewModel; collect with collectAsStateWithLifecycle(); single UiState sealed class/data class","Use LiveData in new Compose code (prefer StateFlow); multiple flows for different state pieces (merge into UiState)","val uiState: StateFlow<HomeUiState> = _uiState.asStateFlow(); @Composable fun Screen(vm: HomeVM) { val state by vm.uiState.collectAsStateWithLifecycle() }","var posts by mutableStateOf(listOf<Post>()) // In composable directly — lost on configuration change",Critical,https://developer.android.com/topic/libraries/architecture/viewmodel
10
+ Accessibility,Provide contentDescription for images and icons,Icon-only buttons and network images have no accessible name without contentDescription; TalkBack announces 'unlabeled' or file name,"contentDescription for informational images and icon buttons; null for decorative images; semantics block for custom roles","Leave contentDescription null on tappable Icon buttons; use generic 'icon' as description; describe appearance not meaning","Icon(Icons.Filled.Favorite, contentDescription = stringResource(R.string.like_post))","Icon(Icons.Filled.Favorite, contentDescription = null) // Tappable icon with no accessible name",Critical,https://developer.android.com/jetpack/compose/accessibility
11
+ Accessibility,Mark headings in semantics for TalkBack navigation,TalkBack supports heading navigation via linear navigation or custom heading navigation; composables without heading role are not navigable as headings,"Use Modifier.semantics { heading() } on screen title and section headers; test with TalkBack heading navigation","Mark every large text as heading (only true headings); use heading for decorative large display text","Text('Your Feed', style=MaterialTheme.typography.headlineSmall, modifier=Modifier.semantics { heading() })","Text('Your Feed', style=MaterialTheme.typography.headlineSmall) // Not navigable as heading by TalkBack",High,https://developer.android.com/jetpack/compose/accessibility#heading
12
+ Animation,Use AnimatedVisibility for show/hide transitions,Instant visibility changes (if visible else null) are jarring; AnimatedVisibility wraps entry/exit animations declaratively,"AnimatedVisibility with customized enter/exit spec; Crossfade for content that changes between states; AnimatedContent for content-changing transitions","Use visibility modifier instead (element still composed); show/hide with alpha 0 (still receives clicks)","AnimatedVisibility(visible=isLoaded, enter=fadeIn()+slideInVertically(), exit=fadeOut()+slideOutVertically()) { Content() }","if (isLoaded) Content() else null // Instant appears no transition",High,https://developer.android.com/jetpack/compose/animation/composables-modifiers#animatedvisibility
13
+ Animation,Respect system animation scale and reduceMotion,Android developer options allow disabling animations; Compose respects AnimatorDurationScale; additionally respect Accessibility reduceMotion setting,"Check LocalReduceMotion or animationsEnabled; use shorter duration or instant for reduceMotion; always support animation scale factor of 0","Play full animations regardless of system animation scale; use hard-coded durations ignoring scale","val reduceMotion = LocalReduceMotion.current; val duration = if (reduceMotion == ReduceMotion.Enabled) 0 else 300; animatedContent(targetState) { target -> transitions based on duration }","tween(durationMillis = 300) // Ignores user animation preferences",High,https://developer.android.com/jetpack/compose/animation/introduction
14
+ Images,Use Coil for async image loading in Compose,Coil integrates with Compose naturally; provides AsyncImage composable with lifecycle-aware loading caching and error handling,"Use AsyncImage from coil3-compose; provide placeholder and error; set model with context+url; use ContentScale matching image usage","Manually download bitMap in coroutine and set to Image (no caching no lifecycle); use Glide with traditional view binding in Compose","AsyncImage(model = ImageRequest.Builder(context).data(url).crossfade(true).build(), contentDescription = 'Profile photo', contentScale = ContentScale.Crop, placeholder = painterResource(R.drawable.placeholder), error = painterResource(R.drawable.error), modifier = Modifier.fillMaxWidth())","LaunchedEffect(url) { val bmp = withContext(Dispatchers.IO) { loadBitmap(url) }; bitmap = bmp } // Manual, no cache",High,https://coil-kt.github.io/coil/compose/
15
+ Theme,Use MaterialTheme tokens for all colors shapes typography,Hardcoded colors break dark mode; non-theme sizes are inconsistent and unmaintainable; theme tokens respond to dynamic color (Android 12+),"Use MaterialTheme.colorScheme.primary surface onBackground etc.; MaterialTheme.typography.headlineMedium; MaterialTheme.shapes.medium","Hardcode Color(0xFFBB86FC) purple; use arbitrary corner radius values not from shapes theme","Surface(color=MaterialTheme.colorScheme.surface, shape=MaterialTheme.shapes.medium) { Text('Hello', style=MaterialTheme.typography.bodyMedium, color=MaterialTheme.colorScheme.onSurface) }","Surface(color = Color(0xFFFFFFFF)) { Text('Hello', fontSize = 16.sp, color = Color.Black) } // Not adaptive",High,https://developer.android.com/jetpack/compose/designsystems/material3
16
+ Testing,Use ComposeTestRule for UI testing,Compose UI tests use ComposeTestRule which provides semantic tree querying; allows testing without knowing implementation,"Use onNodeWithText() onNodeWithContentDescription() onNodeWithTag(); performClick() performScrollTo(); assertIsDisplayed() assertEquals()","Use onNodeWithText for implementation details (fragment class names); use index-based queries that break on content changes","@Test fun login_success() { rule.onNodeWithText('Sign In').performClick(); rule.onNodeWithText('Welcome, Alice').assertIsDisplayed() }","@Test fun test() { rule.onAllNodes(isClickable())[0].performClick() } // Index-based fragile",High,https://developer.android.com/jetpack/compose/testing
17
+ Error Handling,Use sealed classes for UiState to model all screen states,Unmodeled states (loading error empty success) lead to runtime null errors and undefined UI; sealed class forces handling all cases,"Sealed class or sealed interface with Loading Success Error Empty states; when expression exhausts all cases; never skip a state","Use nullable data class with isLoading:Boolean and error:String? (can be in inconsistent combination like isLoading=true AND error!=null)","sealed interface HomeUiState { object Loading : HomeUiState; data class Success(val posts: List<Post>) : HomeUiState; data class Error(val message: String) : HomeUiState }; when(state) { is Loading -> LoadingSpinner() is Success -> PostList(state.posts) is Error -> ErrorView(state.message) }","data class HomeUiState(val posts: List<Post>? = null, val isLoading: Boolean = false, val error: String? = null) // Can be logically inconsistent",High,https://kotlinlang.org/docs/sealed-classes.html
18
+ Performance,Use key() to help Compose identify list item identity,Without keys Compose uses position to identify items; insertions/deletions at start recompose all items; keys allow structural diff,"Provide key in LazyColumn items(key={it.id}); also in Column with key() recompose block for smaller lists; keys must be stable and unique","Use index as key (defeats purpose); change key values (triggers full recompose of that item)","LazyColumn { items(posts, key = { post -> post.id }) { post -> PostCard(post) } }","LazyColumn { itemsIndexed(posts) { index, post -> PostCard(post) } } // Index key — insertion at top recomposes all",High,https://developer.android.com/jetpack/compose/lists#item-keys