Skip to content
cccskills
FreePublished on GitHub

mobile-ui-ux

Use when designing or building any mobile screen or component a user sees (Flutter, SwiftUI or Compose) - platform conventions, hierarchy, type that scales, colour roles and dark mode, safe areas and insets, forms and keyboard, states, feedback, and the generic-mobile anti-patterns.

The English summary is being prepared. Showing the original description.

See how to install

Files included (1)

  • SKILL.md7.2 KB

SKILL.md (original)

Review the instructions the agent will receive before you install.

Mobile UI/UX

Overview

A screen that compiles and passes its widget test has not been designed. The two most common mobile failures are a web-style layout wearing a mobile skin (centred everything, modal-on-modal, a custom tab bar that doesn't match the platform) and a happy-path-only build with no loading/empty/error state.

Core principle: follow the platform's own conventions first, build from theme tokens and the atomic component library, and design every state — not just the one the task's screenshot shows.

Platform conventions

ConcerniOSAndroid
Touch target44×44pt48×48dp
Top-level navigationtab bar, 3–5 itemsnav bar, 3–5 items → nav rail ≥600dp
Backedge swipe, never overriddensystem/predictive back; BackHandler/PopScope, never onBackPressed
TextDynamic Type text stylesMaterial type roles, in sp
Alertscritical onlycritical only
Non-critical feedback—snackbar

Destructive actions carry a destructive role plus a confirmation or an undo window — never a silent delete either platform.

Hierarchy

  • One primary action per screen, placed in the thumb zone (bottom half on a phone held one-handed).
  • Emphasise with size → weight → colour, in that order; de-emphasise secondary content rather than shouting the primary one louder.

Spacing

  • A 4/8 token scale (xs 4, sm 8, md 16, lg 24, xl 32 or the repo's own theme extension) — never a magic numeric literal in a widget/view.
  • Tighter spacing inside a group than between groups.

Typography

  • Theme text styles only (Theme.textTheme, Material type roles, Font semantic styles) — never a fixed/hardcoded size.
  • Body text ≥16px (Flutter/Android) / ≥17pt (iOS); nothing below 11pt/12sp anywhere in the UI.
  • Never a fixed height on a container that holds text — a fixed height clips text at larger font scales.

Colour

  • Roles, not hex: ColorScheme/Theme.of(context).colorScheme, Material colour roles, asset-catalog semantic colours — never Color(0x…)/Colors.* outside the theme files.
  • Contrast ≥4.5:1 body, ≥3:1 large text; status is never colour-only (pair with an icon or text).
  • Dark mode comes from the theme, never a per-widget override. Material 3 dark surfaces are never pure black — use the theme's elevated-surface colour.

Safe areas and insets

  • Flutter: SafeArea, MediaQuery.viewPaddingOf(context).
  • Compose: Scaffold's innerPadding + consumeWindowInsets — don't double-apply padding on top of it.
  • SwiftUI: .ignoresSafeArea() only on a background layer, never on interactive content.
  • A NavigationSuiteScaffold/custom bottom bar doesn't automatically propagate inset padding to its content — verify by looking, don't assume.

Forms and keyboard

  • Correct keyboard type (TextInputType.emailAddress, .keyboardType(.emailAddress), KeyboardOptions(keyboardType = ...)) and autofill hints.
  • An explicit IME action chain: next moves to the following field, the last field is done/submits.
  • The focused field scrolls into view above the keyboard; the submit control stays reachable while the keyboard is open.
  • Inline error next to the field, not a toast; on submit, focus the first invalid field.
  • Never block paste into a field.

States — non-negotiable for every data screen

  • Loading: a skeleton that mirrors the final layout, not a full-screen blocking spinner.
  • Empty: explain why, give one next action.
  • Error: say what happened and offer retry.
  • Success: visible feedback (snackbar/toast, inline confirmation, or a state swap).
  • Pressed and disabled states styled on every control you touch.

Feedback and motion

  • Haptics on confirmations only, never decoratively on every tap.
  • Respect the reduce-motion setting (see mobile-accessibility); prefer no animation over a gratuitous one.

Imagery

  • One icon set per app (SF Symbols or Material Symbols, not both) — consistent size and weight.
  • Never an emoji standing in for an icon in shipped UI.

Copy

  • UI copy in the app locale (see app-locale-ui-copy); no leftover placeholder text.

Anti-generic-mobile list — refuse these unless the brief explicitly asks for them

  • A hamburger menu on iOS (use a tab bar or a clear in-context action).
  • Centred-everything layout as the page structure.
  • A web-style modal stacked on another modal.
  • A FAB used for a secondary action — reserve it for the one primary action on the screen.
  • A card nested inside a card.
  • Gradient text; grey text on a coloured surface.
  • A custom-painted imitation of the platform's own tab bar / nav bar instead of using the platform component.
  • A full-screen spinner where a skeleton belongs.

Worked Example

// ❌ fixed Row, hardcoded style, no layout adaptation —
// passes at text scale 1.0, overflows 82px on the right at 360 wide / text scale 2.0
Row(
  children: [
    Expanded(child: Text(task.title, style: const TextStyle(fontSize: 16))),
    Text(task.price),
    IconButton(icon: const Icon(Icons.add), onPressed: onAdd),
  ],
)

// ✅ decides by available width and text scale, themed, labeled
LayoutBuilder(
  builder: (context, constraints) {
    final narrow = constraints.maxWidth < 280 * MediaQuery.textScalerOf(context).scale(1);
    final price = Text(task.price, style: context.textTheme.bodyMedium);
    final addButton = IconButton(
      icon: const Icon(Icons.add),
      tooltip: 'Add to cart',
      onPressed: onAdd,
    );
    final title = Text(task.title, style: context.textTheme.titleMedium);
    return narrow
        ? Column(crossAxisAlignment: CrossAxisAlignment.start, children: [
            title,
            Row(children: [Expanded(child: price), addButton]),
          ])
        : Row(children: [Expanded(child: title), price, addButton]);
  },
)

The rewrite decides layout from the available width instead of assuming it, uses theme text styles so it scales with the system font size, and labels the icon-only button. See mobile-visual-self-review for the verified matrix test that caught the overflow.

Common Mistakes

  • Shipping a screen's happy path only — no loading skeleton, no empty state, no error recovery.
  • Color(0x…)/Colors.*/hardcoded fontSize/magic EdgeInsets instead of theme tokens.
  • An icon-only control with no accessibility label.
  • Deciding layout by device type or orientation instead of available width.
  • Locking screen orientation — ignored on Android 16+ for screens ≥600dp.

Red Flags

  • A screen with only one state rendered in the diff.
  • A hardcoded colour or font size anywhere outside the theme files.
  • Two screens showing visually different buttons built independently instead of from the same atom.
  • A fixed-height container wrapping a Text/label.

Reviews

No reviews yet. Tell others what you thought.

Comments

No login needed. Share how it worked for you, ask a question, or note where it did not run.

No comments yet. Be the first to write one.

Comments are published right away. Do not include personal information such as email addresses or phone numbers. Up to 2 URLs.

0 / 1,000 characters

This form is protected by reCAPTCHA, and the Google Privacy Policy and Terms of Service apply.

More skills from this repository

Use when writing acceptance criteria for a task - express each as an observable Given/When/Then that QA can execute, including negative cases

The English summary is being prepared. Showing the original description.

makifbaysal/tasktrooper117Updated Oct 21, 2026

Use when the diff adds or changes an endpoint, resolver, RPC, job or query that takes an object id, a role check, a request binding or a tenant filter - BOLA/IDOR, function-level authorization, mass assignment and tenant scoping

The English summary is being prepared. Showing the original description.

makifbaysal/tasktrooper117Updated Oct 21, 2026

Use on every UI change - semantic HTML, labels for controls, keyboard-navigable dialogs/menus, visible focus, and never color as the only signal

The English summary is being prepared. Showing the original description.

makifbaysal/tasktrooper117Updated Oct 21, 2026

Use when a task changes any screen, form, dialog, menu or control - Lighthouse/axe scan of the changed screens, a keyboard walk, and the thresholds that fail a task

The English summary is being prepared. Showing the original description.

makifbaysal/tasktrooper117Updated Oct 21, 2026

How to work a task returned with review, QA or UAT findings. Use when a task is in need_revision or PR review comments are in your context.

The English summary is being prepared. Showing the original description.

makifbaysal/tasktrooper117Updated Oct 21, 2026

Use when the repository keeps its alerting in code, or a person asks for alerts outside TaskTrooper - PrometheusRule YAML, a Cloud Monitoring alert policy in Terraform, a Datadog monitor, each routed to TaskTrooper's alert ingest URL so it opens an incident here

The English summary is being prepared. Showing the original description.

makifbaysal/tasktrooper117Updated Oct 21, 2026

See all skills by makifbaysal

Report a problem with this skill