Files
nexu-io-open-design/skills/mobile-onboarding/SKILL.md
Mohamed Abdallah d80402a8ca craft: add form-validation so generated forms aren't stuck in 2018 RHF/Formik patterns (#625)
* feat(craft): add form-validation + opt-ins on saas-landing, mobile-onboarding

Module 5 of 5 in the behavioral craft series proposed in #501.
Modules 1-4 merged: state-coverage (#502), animation-discipline (#515),
accessibility-baseline (#587), rtl-and-bidi (#595).

Picks up where accessibility-baseline.md ends (label + describedby +
invalid + role=alert for inline errors) and connects the four layers a
real form spans: WHATWG Constraint Validation as the platform floor,
validation timing as a state machine on the input, WCAG 3.3.x as the
announcement and recovery contract, schema as the cross-stack truth.

Sections: input state machine; validation timing (4 rules anchored on
:user-invalid Baseline 2023); Constraint Validation API rules
(setCustomValidity, requestSubmit vs submit, readonly + #11841,
inputmode); error wiring beyond the baseline (adaptive messages,
error summary without role=alert, preserve user input on error);
schema as cross-stack contract (Standard Schema, server-authoritative,
Zod 4 z.email() form); WCAG 3.3.3 / 3.3.4 / 3.3.8 / 3.3.9; native
mobile parity (UIKit, SwiftUI, Compose, Flutter, RN); common mistakes.

Reviewed in 3 loops with Claude CLI Opus 4.7 xhigh effort:
- Loop 1: 6 P0s caught (SwiftUI Form validity claim, SwiftUI
  announcement primitive, Compose semantics syntax, UIKit
  UIAlertController, contradictory Baymard stats, 3.3.8 CAPTCHA
  framing reversed) + 11 P1/P2s; all addressed.
- Loop 2: verified P0 fixes; flagged 1 P1 (RN table row scrambled) +
  4 P2s; all addressed.
- Loop 3: SHIP verdict. Three P2 nits applied (Zod 4 z.email() form,
  WebAIM Million 2026 stat woven in: 51% page-level, 33.1% input-level).

WebAIM Million 2026 numbers verified directly against
webaim.org/projects/million/.

Skill opt-ins: saas-landing (lead capture form), mobile-onboarding
(sign-in screen). Skill bodies do not contain validation-specific
instructions that would override craft guidance — opt-in alone is
sufficient. README updated.

Refs #501.

* fix(craft+skills): form-validation review fixes (lefarcen + mrcfps P2s)

Both non-blocking findings addressed:

- Drop form-validation from saas-landing.craft.requires. The skill body
  produces a CTA-driven landing page with no JS and no interactive
  form. Adding form-validation injected ~221 lines of irrelevant prompt
  pressure and conflicted with the README opt-in rule ("primary
  artifact contains an interactive form"). mobile-onboarding keeps the
  opt-in — sign-in screen is a real form.
- Reword timing rule 4 (async checks). Previous "never block submit on
  a network round-trip" was too broad and conflicted with the
  schema-layer "server is the truth" rule. Split into two paths:
  background preflight (uniqueness, address lookup) doesn't gate the
  form; authoritative submit-path server validation must await the
  server response and surface its field errors. The rule is "don't let
  a slow background check freeze the form," not "don't ever wait for
  the server."

* fix(craft): form-validation mrcfps round-2 (novalidate trade-off, Flutter RTL)

Two non-blocking precision items:

- novalidate trade-off: previous wording said keeping required/pattern/type
  preserves no-JS PE, but a literal server-rendered <form novalidate>
  disables the browser's submit-blocking and validation UI even when
  JS is unavailable — losing the no-JS constraint-validation floor.
  Reworded to spell out the two safe patterns: (A) render <form>
  without novalidate server-side and have the form library set
  form.noValidate = true after hydration, or (B) ship novalidate from
  the start only when the submit path reaches server validation
  without JS. Either way, keep the constraint attributes.
- Flutter announcement example: hardcoded TextDirection.ltr would
  announce Arabic/Hebrew/Persian validation messages with wrong bidi
  direction when this craft is combined with rtl-and-bidi. Switched
  to SemanticsService.announce(message, Directionality.of(context))
  with an explicit warning never to hardcode the direction.

* fix(craft): form-validation mrcfps round-3 (readonly safety, Compose error message)

Two non-blocking precision items:

- Non-input readonly fallback: previous text said `aria-readonly` plus
  hidden mirror input was an option for non-input controls that need
  to submit. But `aria-readonly` doesn't actually stop a `<select>` or
  custom widget from being changed, so the visible control can drift
  while the hidden input ships a stale value — user sees one option,
  server gets another. Tightened: prefer `disabled` plus a same-named
  hidden input, or non-editable text plus hidden input. If using
  `aria-readonly`, the interaction must also be blocked or the two
  values kept in sync.
- Compose error message: previous rule was too absolute about avoiding
  `Modifier.semantics { error("…") }`. `isError = true` flips the
  field state but does not carry the localized error message; Android
  Compose accessibility guidance pairs `isError` with
  `semantics { error(message) }` so the accessibility service gets the
  real text. The trap is duplication, not the API itself. Reframed
  the rule: use both, source the message from the same state field as
  `supportingText` so they stay in sync.

* fix(craft): form-validation Compose live-region API name

Compose row in the native-mobile parity table named a "LiveRegion"
semantic that doesn't exist. Real API is `Modifier.semantics
{ liveRegion = LiveRegionMode.Polite }` on the supporting-text node.
Also replaced the generic `view.announceForAccessibility(…)` with the
Compose-idiomatic `LocalView.current.announceForAccessibility(message)`
so generated snippets compile.
2026-05-06 20:09:30 +08:00

1.5 KiB

name, description, triggers, od
name description triggers od
mobile-onboarding A multi-screen mobile onboarding flow rendered as three phone frames side by side — splash, value-prop, sign-in. Status bar, swipe dots, primary CTA. Use when the brief mentions "mobile onboarding", "iOS onboarding", "phone signup", or "移动端引导".
mobile onboarding
ios onboarding
android onboarding
phone signup
app onboarding
移动端引导
mode platform scenario featured preview design_system craft example_prompt
prototype mobile design 13
type entry
html index.html
requires sections
true
color
typography
layout
components
requires
state-coverage
animation-discipline
accessibility-baseline
form-validation
Design a 3-screen mobile onboarding flow for a meditation app — welcome, value props, sign-in.

Mobile Onboarding Skill

Produce a three-screen mobile onboarding flow on a single HTML page.

Workflow

  1. Read DESIGN.md.
  2. Identify the app + audience.
  3. Layout: three phone frames side by side. Each phone:
    • Status bar (time, battery, signal).
    • Hero artwork or icon.
    • Headline + supporting paragraph.
    • 3-dot pagination.
    • Primary CTA (full-width pill button).
    • "Skip" or alt action top-right.
  4. Last phone is the sign-in / continue-with options screen.
  5. Strong typography, gentle gradients, accessible contrast.

Output contract

<artifact identifier="mobile-onboarding-name" type="text/html" title="Mobile Onboarding">
<!doctype html>...</artifact>