# Common Rules for Professional UI + Pre-Delivery Checklist Load this file before final delivery of native/mobile app UI (iOS/Android/React Native/Flutter), or when the user reports the UI "doesn't look professional" and the cause isn't obvious from the priority table in SKILL.md. **Scope notice:** everything below targets native/mobile app UI. For web/desktop interaction patterns, use `references/quick-reference.md` (stack-agnostic) instead โ€” these tables assume touch targets, safe areas, and platform gesture conventions that don't apply 1:1 to desktop web. These are frequently overlooked issues that make UI look unprofessional. ## Icons & Visual Elements | Rule | Standard | Avoid | Why It Matters | |------|----------|--------|----------------| | **No Emoji as Structural Icons** | Use vector-based icons (e.g., Lucide, react-native-vector-icons, @expo/vector-icons). | Using emojis (๐ŸŽจ ๐Ÿš€ โš™๏ธ) for navigation, settings, or system controls. | Emojis are font-dependent, inconsistent across platforms, and cannot be controlled via design tokens. | | **Vector-Only Assets** | Use SVG or platform vector icons that scale cleanly and support theming. | Raster PNG icons that blur or pixelate. | Ensures scalability, crisp rendering, and dark/light mode adaptability. | | **Contextual Semantics** | Choose semantics from use, not glyph: hide decorative icons beside visible text from the accessibility tree; give meaningful standalone icons a text alternative; give icon controls an accessible name and expose selected/pressed/expanded state when applicable. | Treating one icon name as permanently decorative, meaningful, or interactive. | The same glyph can serve different purposes in different components. | | **Stable Interaction States** | Use color, opacity, or elevation transitions for press states without changing layout bounds. | Layout-shifting transforms that move surrounding content or trigger visual jitter. | Prevents unstable interactions and preserves smooth motion/perceived quality on mobile. | | **Correct Brand Logos** | Use official brand assets and follow their usage guidelines (spacing, color, clear space). | Guessing logo paths, recoloring unofficially, or modifying proportions. | Prevents brand misuse and ensures legal/platform compliance. | | **Consistent Icon Sizing** | Define icon sizes as design tokens (e.g., icon-sm, icon-md = 24pt, icon-lg). | Mixing arbitrary values like 20pt / 24pt / 28pt randomly. | Maintains rhythm and visual hierarchy across the interface. | | **Stroke Consistency** | Use a consistent stroke width within the same visual layer (e.g., 1.5px or 2px). | Mixing thick and thin stroke styles arbitrarily. | Inconsistent strokes reduce perceived polish and cohesion. | | **Filled vs Outline Discipline** | Use one icon style per hierarchy level. | Mixing filled and outline icons at the same hierarchy level. | Maintains semantic clarity and stylistic coherence. | | **Touch Target Minimum** | Use at least 44pt on iOS and 48dp on Android; expand the hit area when the visual icon is smaller. | Small icons without expanded tap area, or one unit reused across platforms. | Matches platform-specific target guidance. | | **Icon Alignment** | Align icons to text baseline and maintain consistent padding. | Misaligned icons or inconsistent spacing around them. | Prevents subtle visual imbalance that reduces perceived quality. | | **Icon Contrast** | Meaningful icons and control boundaries need at least 3:1 against adjacent colors; decorative icons must not carry information. | Low-contrast icons that carry meaning or state. | Applies the non-text contrast role instead of a text-size rule. | ## Interaction (App) | Rule | Do | Don't | |------|----|----- | | **Tap feedback** | Provide clear pressed feedback (ripple/opacity/elevation) within 80-150ms | No visual response on tap | | **Animation timing** | Use shared tokens chosen for distance, complexity, platform, and user context | One duration/easing copied to every transition | | **Accessibility focus** | Ensure screen reader focus order matches visual order and labels are descriptive | Unlabeled controls or confusing focus traversal | | **Disabled state clarity** | Use disabled semantics (`disabled`/native disabled props), reduced emphasis, and no tap action | Controls that look tappable but do nothing | | **Touch target minimum** | Keep tap areas >=44x44pt (iOS) or >=48x48dp (Android), expand hit area when icon is smaller | Tiny tap targets or icon-only hit areas without padding | | **Gesture conflict prevention** | Keep one primary gesture per region and avoid nested tap/drag conflicts | Overlapping gestures causing accidental actions | | **Semantic native controls** | Prefer native interactive primitives (`Button`, `Pressable`, platform equivalents) with proper accessibility roles | Generic containers used as primary controls without semantics | ## Light/Dark Mode Contrast | Rule | Do | Don't | |------|----|----- | | **Surface readability (light)** | Keep cards/surfaces clearly separated from background with sufficient opacity/elevation | Overly transparent surfaces that blur hierarchy | | **Text contrast (light)** | Maintain body text contrast >=4.5:1 against light surfaces | Low-contrast gray body text | | **Text contrast (dark)** | Maintain normal text contrast >=4.5:1 on dark surfaces; 3:1 is only for large text or non-text UI | Muted normal text that falls below the text threshold | | **Border and divider visibility** | Ensure separators are visible in both themes (not just light mode) | Theme-specific borders disappearing in one mode | | **State contrast parity** | Keep pressed/focused/disabled states equally distinguishable in light and dark themes | Defining interaction states for one theme only | | **Token-driven theming** | Use semantic color tokens mapped per theme across app surfaces/text/icons | Hardcoded per-screen hex values | | **Scrim and modal legibility** | Measure the composed result and use a scrim strong enough to isolate foreground content | Reusing one opacity without checking the actual background | ## Layout & Spacing | Rule | Do | Don't | |------|----|----- | | **Safe-area compliance** | Respect top/bottom safe areas for all fixed headers, tab bars, and CTA bars | Placing fixed UI under notch, status bar, or gesture area | | **System bar clearance** | Add spacing for status/navigation bars and gesture home indicator | Let tappable content collide with OS chrome | | **Consistent content width** | Keep predictable content width per device class (phone/tablet) | Mixing arbitrary widths between screens | | **8dp spacing rhythm** | Use a consistent 4/8dp spacing system for padding/gaps/section spacing | Random spacing increments with no rhythm | | **Readable text measure** | Keep long-form text readable on large devices (avoid edge-to-edge paragraphs on tablets) | Full-width long text that hurts readability | | **Section spacing hierarchy** | Define clear vertical rhythm tiers (e.g., 16/24/32/48) by hierarchy | Similar UI levels with inconsistent spacing | | **Adaptive gutters by breakpoint** | Increase horizontal insets on larger widths and in landscape | Same narrow gutter on all device sizes/orientations | | **Scroll and fixed element coexistence** | Add bottom/top content insets so lists are not hidden behind fixed bars | Scroll content obscured by sticky headers/footers | --- ## Pre-Delivery Checklist (canonical โ€” the only one) Before delivering app UI code, verify every item below. Start with the process steps, then the per-area checkboxes. ### Process - [ ] Ran only searches relevant to the interface, such as `"keyboard focus modal" --domain ux` for modal keyboard behavior - [ ] Reviewed `quick-reference.md` ยง1โ€“ยง3 (CRITICAL + HIGH) as a final pass - [ ] Tested on 375px (small phone) and in landscape orientation - [ ] Verified behavior with **reduced-motion** enabled and **Dynamic Type**/largest system text size - [ ] Checked dark mode contrast independently (never assume light-mode values carry over) - [ ] Confirmed all touch targets โ‰ฅ44pt and no content hidden behind safe areas ### Visual Quality - [ ] No emojis used as icons (use SVG instead) - [ ] All icons come from a consistent icon family and style - [ ] Official brand assets are used with correct proportions and clear space - [ ] Pressed-state visuals do not shift layout bounds or cause jitter - [ ] Semantic theme tokens are used consistently (no ad-hoc per-screen hardcoded colors) ### Interaction - [ ] All tappable elements provide clear pressed feedback (ripple/opacity/elevation) - [ ] Touch targets meet minimum size (>=44x44pt iOS, >=48x48dp Android) - [ ] Micro-interaction timing uses shared, platform-appropriate tokens and remains responsive in context - [ ] Disabled states are visually clear and non-interactive - [ ] Screen reader focus order matches visual order, and interactive labels are descriptive - [ ] Gesture regions avoid nested/conflicting interactions (tap/drag/back-swipe conflicts) ### Light/Dark Mode - [ ] Primary text contrast >=4.5:1 in both light and dark mode - [ ] Normal primary and secondary text contrast >=4.5:1 in both light and dark mode - [ ] Dividers/borders and interaction states are distinguishable in both modes - [ ] Modal/drawer scrim is measured against the real background and preserves foreground legibility - [ ] Both themes are tested before delivery (not inferred from a single theme) ### Layout - [ ] Safe areas are respected for headers, tab bars, and bottom CTA bars - [ ] Scroll content is not hidden behind fixed/sticky bars - [ ] Verified on small phone, large phone, and tablet (portrait + landscape) - [ ] Horizontal insets/gutters adapt correctly by device size and orientation - [ ] 4/8dp spacing rhythm is maintained across component, section, and page levels - [ ] Long-form text measure remains readable on larger devices (no edge-to-edge paragraphs) ### Accessibility - [ ] Decorative icons beside visible text are hidden from the accessibility tree (`aria-hidden="true"` on web or the native equivalent) - [ ] Meaningful images/icons without equivalent visible text have a text alternative - [ ] Icon controls have an accessible name and announce applicable selected/pressed/expanded state - [ ] Form fields have labels, hints, and clear error messages - [ ] Color is not the only indicator - [ ] Reduced motion and dynamic text size are supported without layout breakage - [ ] Sticky UI and overlays do not obscure keyboard focus - [ ] Dragging and swipe-only interactions have button/keyboard alternatives - [ ] Authentication allows password managers and paste, with a non-cognitive alternative - [ ] Auto-rotating content has pause/stop controls and stops on focus or reduced motion - [ ] Failed forms retain inline field errors; multi-error forms also focus a linked error summary after submit