Consumer Design System · v1.39.0 · 2026
Built for products that billions of people touch.
A business-to-consumer design system: 190 component categories across seventeen domains — commerce, social, media, onboarding, growth, trust, AI & agents, text animation, and spatial & direct manipulation. Every entry carries a decision register, an accessibility contract, and a platform anchor. Humans copy the code below each preview; agents read the machine contracts. Same bytes, two doors.
Consumer pet-travel planning surfaces using the system's onboarding, cards, trust, and mobile-first interaction patterns.
Used in product DuoShouA consumer AI shopping assistant applying the commerce, recommendation, disclosure, and dark-pattern-free growth rules.
Used in product WizAgentsAn expert-agent marketplace using CDS AI-agent patterns: subscriptions, MCP tokens, auditability, and human escalation.
Claude
ChatGPT
Codex
Gemini
Antigravity
Cursor
Figma MCP
Grok
DeepSeek
Qwen
Hermes Agent
OpenClaw
NVIDIA
Hugging Face
Ollama
n8n
Dify
Cline
OpenCode
Z.ai
Eigent AI
Copilot
Kimi
Llama
Docker
AutoGPT
Mem0
Voyager
Manus
Pydantic AI
CrewAI
OpenHands
Claude Cowork
ZeroClawThe contracts are plain JSON — whatever you already run can read this system.
Original, independent work. This system cites public platform guidelines — Apple Human Interface Guidelines, Material Design 3, WCAG 2.2, App Store Review Guidelines, Google Play policy, GDPR, COPPA, FTC rules — as design constraints, the way a building cites a building code. It is the consumer-market counterpart to the Institutional Finance Design System: same discipline, different physics — where the institutional system optimises for density and auditability, this one optimises for clarity, delight, and trust at scale.
The domain map
Counts are computed at runtime from the live navigation — they can never drift from the sidebar. Click a domain to filter.
What every entry carries
The entry contract
4-cell register · live preview · copyable code · machine contractRendered from the same tokens the code uses — light and dark, no screenshots.
The job the component exists for, stated so a reviewer can check it.
A system that can't say no isn't a system. Every entry names its misuse.
Focus, labels, target sizes, reduced motion — the behaviour that must survive a redesign.
A public guideline the entry answers to — HIG, Material 3, WCAG 2.2, store policy, GDPR, COPPA, FTC.
Design principles
Clarity before cleverness
Consumer attention is borrowed, not owned. Every screen answers "what is this, what can I do" in the first glance — decoration never competes with the answer.
Deference to content
The interface is the frame, not the painting. Glass, hairlines, and restraint keep the user's photos, products, and words as the loudest thing on screen.
Motion is physics, not garnish
Motion explains where things came from and where they went. Through v1.29 that meant one spring curve everywhere; from v1.30 it means one curve per role — Navigation, Ambient, Reveal, Commit, Settle — because a duration scale answers how big an element is, not what the movement is doing to the user. Both are still one decision, taken once, in tokens. Every animation respects prefers-reduced-motion as a contract, not a suggestion.
Touch first, then scale up
44px minimum targets, thumb-reach layouts, bottom sheets over centered dialogs on small screens. Desktop is the enhancement, not the default.
Trust is a feature
Consent is real, cancellation takes as few steps as signup, and growth components persuade without trapping. The FTC's word for the alternative is a rule violation; ours is a design failure.
One contract, two readers
Humans read the previews; agents read tokens.json and components.json — generated from this page, so the two can never disagree.
Start · Machine Layer
The system agents can read.
Two JSON contracts and a drop-in agent brief ship alongside this page. They are not documentation about the system — they are the system, in a shape a tool call can consume. The component index is generated from this page's own navigation, so it can never drift from what you're looking at.
Readable by whatever you already run
Claude
ChatGPT
Codex
Gemini
Antigravity
Cursor
Figma
MCP
Grok
DeepSeek
Qwen
Hermes
Agent
OpenClaw
NVIDIA
Hugging
Face
Ollama
n8n
Dify
Cline
OpenCode
Z.ai
Eigent
AI
Copilot
Kimi
Llama
Docker
AutoGPT
Mem0
Voyager
Manus
Pydantic
AI
CrewAI
OpenHands
Claude
Cowork
ZeroClaw
The contracts are plain JSON over HTTPS — anything that can fetch a URL or speak MCP can consume them, cloud assistants and on-prem open-weight models alike.
The read path — how an agent consumes this system
This is the reading logic, step by step. It isn't prose an agent might follow — steps 1–4
ship inside components.json itself as agentProtocol,
bundles, and hardRules, so any agent that fetches the index receives its own
instructions with the data.
Discover
An agent landing anywhere on this page finds the machine layer without parsing the HTML: two
link rel="alternate" hints in the head, Dataset structured data, and the site-level llms.txt
all point at the same two files.
<link rel="alternate">Dataset JSON-LDllms.txt
Fetch the index
One GET returns all 190 entries carrying their whole decision register — when to use, when not to, the behaviour & accessibility contract, the platform anchor, and the canonical URL — plus the protocol itself. An agent never has to parse the HTML to build compliantly. Generated from this page's own navigation: what the agent reads and what you're reading cannot disagree.
GET cds/components.json
Select, never invent
Entries are chosen by matching domain and summary against the brief. A component that isn't in the index doesn't exist — the agent's creativity budget is spent inside contracts, not around them.
filter: domain + summary
Read the register
Each entry's URL deep-links to its four-cell register. The when-not-to cell is binding — a brief that asks for a component inside its own named misuse gets a refusal with a citation, and the anchor is a constraint, not a footnote.
entry.url → #registerwhen-not-to: binding
Resolve bundles & hard rules
Some components require others — paywall ships with cancellation, UGC ships with report & block, checkout shows the all-in total. Bundles auto-include; hard rules (COPPA, truthful LIVE, symmetric consent) can block the build outright.
bundles[]hardRules[] → BLOCK
Build from tokens
The agent pulls the token slice it needs — never raw hex — inheriting both themes, the single spring curve, and the reduced-motion contract in one fetch.
GET cds/tokens.jsonno raw hex
Gate to a human
Anything irreversible — money, sends, permissions — stops at a confirmation gate that authorises an exact payload, not a plan. The trace logs effects and blocked steps with the rule that blocked them. The model produces; the human signs.
agent-confirm gatetrace: effects + blocks
Connect it
No server, no install. Point any agent, script, or CI job at the two files — the component index carries every entry's id, domain, summary, platform anchor, and canonical URL.
The institutional sibling already ships this way — and since eds-mcp v1.17.0 it serves these files
too: 29 tools, 65 institutional contracts and this 190-entry consumer catalogue from one engine.
These
contracts share the same shape, so a cds-mcp server would be a thin adapter over the same two files —
which is exactly why one has not been written. components.json now carries a
mcp.toolsToFileMapping block naming which slice of which file each tool reads, so the server
is reproducible from the contract rather than trusted.
What a tool call sees
The two JSON files are real and downloadable today, and eds-mcp v1.17.1 (29 tools) serves them over MCP — the same engine that already serves the institutional system's 65 contracts. Payload shapes in the console above are simplified for reading.
Local models and air-gapped networks
Adding the full decision register to every entry made this contract better for a hosted agent
and three times worse for a local one: the index is now 296.4 KB, roughly
75.9K tokens, which is the entire window of most models people actually run on their own
hardware. So the same generated data is also written at four smaller sizes. One
node cds/generate.mjs run produces all of them, which is the only reason they can be trusted to
agree.
| Load this | Size | ≈ tokens | What it holds |
|---|---|---|---|
cds/RULES.txt |
4.2 KB | 1.1K | protocol, hard rules, bundles, the non-negotiables — the whole contract in prose |
cds/tokens.json |
19.3 KB | 4.9K | both themes, all contrast pairs, the motion contract |
cds/domains/<domain>.json |
6.1–44.8 KB | 1.6–11.5K | the full register for one domain only — 17 shards, 6–41 entries each |
cds/index.slim.json |
54.1 KB | 13.9K | id, name, domain, summary for all — enough to choose, not enough to build |
cds/components.json |
296.4 KB | 75.9K | everything, full register per entry — for hosted agents and CI |
Rules card + tokens + one domain shard is 7.6K tokens at the smallest domain and
17.5K at the largest (core, 41 entries). Three domains —
growth, media, navigation — fit inside an 8K window whole;
every domain fits a 32K one with room to write in. And it is complete: the model has the refusal
conditions, both themes, and the full register for everything it is allowed to use. Nothing is fetched at
build time.
None of this is an API. There is no server to reach, no key to rotate, no schema to compile, and no
embedding index to rebuild. Fetch the files once, commit them beside your code, and the contract keeps
working on a machine with the network off — including
node cds/verify.mjs, which is zero-dependency and runs against the checkout rather than the
site.
Why the shards can be trusted. They are not a second copy maintained by hand. Every tier is
written by the same generator run from the same components array, and
cds/verify.mjs asserts it: the 17 shards must hold 190 components between them, the slim
index must list the same ids in the same order, and the rules card must contain every hard rule by id
— a card that silently drops a blocking rule is worse than no card at all.
Make it yours — and prove you did not break it
Most systems let you re-brand into an accessibility violation in silence: you change a hex, the page still renders, and nobody finds out until an audit. Here the tokens are the input to a measurement, so a re-brand that fails cannot be written to disk.
Eighty tokens per theme, but a re-brand is a handful of them. Everything else — radii, spacing,
the twelve motion primitives, the five motion roles, the attenuation floor — is structure, and
changing it changes behaviour rather than identity. Override in a stylesheet that loads after the system, or
edit the
:root and [data-theme="dark"] blocks directly if you have forked the page.
The token file is not hand-maintained — it is read back out of the page and the contrast matrix is recomputed from your hex values. If any of the 44 pairs per theme drops under 4.5:1, the generator exits non-zero and does not write the file. You cannot ship a re-brand that quietly failed, because the artefact never gets produced.
What a re-brand does not license. Three tokens are load-bearing for meaning, not for
taste: --red carries destructive and error semantics, --green carries confirmed
state, and --csp-floor is the opacity at which receding context stops being readable. Re-pointing
the
first two at brand colours — or lowering the third for atmosphere — breaks the
when-not-to cell of every component that relies on them — and the
register, not the palette, is what an agent is holding you to. If you need a brand red, add a token beside
--red rather than over it.
Measured, not claimed
This page cites WCAG 2.2 dozens of times, so it owes you its own numbers. Every ratio below
is computed from the raw hex values in tokens.json — and the contract is
self-testing: node cds/verify.mjs re-runs 4,058 assertions (page ↔ index parity, anchors,
bundles, skills, and this exact table) against your checkout or against the live site
(node cds/verify.mjs https://edwson.com). Exit code 0 or it isn't true.
| Text pair | Light | Dark |
|---|---|---|
| Primary text on pagetext1 / bg | 16.28 AAA | 19.29 AAA |
| Primary text on cardtext1 / surface | 16.83 AAA | 17.43 AAA |
| Primary text on inset paneltext1 / surface2 | 15.46 AAA | 15.91 AAA |
| Primary text on raised chiptext1 / surface3 | 14.28 AAA | 13.78 AAA |
| Secondary text on pagetext2 / bg | 5.52 AA | 8.16 AAA |
| Secondary text on cardtext2 / surface | 5.71 AA | 7.38 AAA |
| Secondary text on inset paneltext2 / surface2 | 5.24 AA | 6.73 AA |
| Secondary text on raised chiptext2 / surface3 | 4.85 AA | 5.84 AA |
| Tertiary / hint text on pagetext3 / bg | 5.13 AA | 6.35 AA |
| Tertiary / hint text on cardtext3 / surface | 5.30 AA | 5.74 AA |
| Tertiary / hint text on inset paneltext3 / surface2 | 4.87 AA | 5.24 AA |
| Tertiary / hint text on raised chiptext3 / surface3 | 4.50 AA | 4.54 AA |
| Accent text & links on pageaccent / bg | 4.95 AA | 6.49 AA |
| Accent text & links on cardaccent / surface | 5.11 AA | 5.87 AA |
| Accent text & links on inset panelaccent / surface2 | 4.69 AA | 5.36 AA |
| Accent text & links on accent panelaccent / accent-soft | 4.54 AA | 4.76 AA |
| Success text on pagegreen / bg | 4.89 AA | 9.19 AAA |
| Success text on cardgreen / surface | 5.05 AA | 8.31 AAA |
| Success text on inset panelgreen / surface2 | 4.64 AA | 7.58 AAA |
| Success text on success panelgreen / green-soft | 4.53 AA | 6.66 AA |
| Error text on pagered / bg | 4.99 AA | 7.45 AAA |
| Error text on cardred / surface | 5.15 AA | 6.73 AA |
| Error text on inset panelred / surface2 | 4.73 AA | 6.14 AA |
| Error text on error panelred / red-soft | 4.51 AA | 6.06 AA |
| Warning text on pageamber / bg | 4.84 AA | 10.08 AAA |
| Warning text on cardamber / surface | 5.01 AA | 9.11 AAA |
| Warning text on inset panelamber / surface2 | 4.60 AA | 8.31 AAA |
| Warning text on warning panelamber / amber-soft | 4.56 AA | 7.60 AAA |
| Accent-2 text on pagepurple / bg | 5.04 AA | 7.69 AAA |
| Accent-2 text on cardpurple / surface | 5.20 AA | 6.95 AA |
| Accent-2 text on inset panelpurple / surface2 | 4.78 AA | 6.34 AA |
| Accent-2 text on accent-2 panelpurple / purple-soft | 4.54 AA | 6.02 AA |
| Tertiary / hint text on accent paneltext3 / accent-soft | 4.71 AA | 4.66 AA |
| Secondary text on accent paneltext2 / accent-soft | 5.07 AA | 5.99 AA |
| Tertiary / hint text on success paneltext3 / green-soft | 4.76 AA | 4.60 AA |
| Secondary text on success paneltext2 / green-soft | 5.13 AA | 5.92 AA |
| Tertiary / hint text on error paneltext3 / red-soft | 4.64 AA | 5.17 AA |
| Secondary text on error paneltext2 / red-soft | 5.00 AA | 6.65 AA |
| Tertiary / hint text on warning paneltext3 / amber-soft | 4.82 AA | 4.79 AA |
| Secondary text on warning paneltext2 / amber-soft | 5.19 AA | 6.16 AA |
| Tertiary / hint text on accent-2 paneltext3 / purple-soft | 4.62 AA | 4.98 AA |
| Secondary text on accent-2 paneltext2 / purple-soft | 4.98 AA | 6.40 AA |
| Button label on accent fill on accent fillaccent-fg / accent | 5.11 AA | 6.27 AA |
| Button label on destructive fill on destructive fillred-fg / red | 5.15 AA | 6.83 AA |
Honesty note: the first run of this table failed — light-theme hint text measured 2.49:1 and the status colours missed 4.5:1 as body text. v1.18.0 changed the tokens, not the claim.
Start · AI-native
Build a screen with an agent.
Pick a brief. Watch an agent read the machine contracts, assemble the screen from this catalogue, and — when the rules demand it — get told no. This is the point of shipping contracts, not documentation: the register every entry carries is enforceable, so the system can refuse a bad build before a human reviewer ever sees it.
A canned walkthrough against the real component index. Every component chip jumps to the real entry; every rule cited is written in that entry's register. An MCP-connected agent runs the same loop against the same files.
Start · AI-native
Design Agent Mode.
An adversarial operating mode for product strategy: six personas, four strict steps, binding constraints. Load it into any capable agent and a raw idea comes back as a stress-tested, quantified, gap-anchored plan — because a single agreeable voice produces agreeable plans, and the friction between lenses is where a plan gets real.
The team — six lenses
Market Gap Hunter 市場ギャップハンター
Hunts unmet gaps, user pain, competitive whitespace, and the timing window. Every claimed gap needs an observable signal, not a vibe.
Product Architect プロダクトアーキテクト
Owns architecture, experience logic and innovation shape — benchmarked against the best-crafted products of the era, designed for extensibility and felt quality.
Business Logic Commander ビジネス戦略司令官
CPO lens: business model, monetization, growth flywheel, one North Star Metric. No plan leaves without an economic engine.
Risk & Feasibility Slayer リスク狙撃手
Investor + COO lens: attacks feasibility, cost structure, technical debt and execution barriers. Its job is to be right, not liked.
Empathy & Validation Engineer 共感・検証エンジニア
Behavioural evidence lens: every feature traces to a real behaviour or validated pain — assumptions get flagged as assumptions.
Delivery & Momentum Accelerator 実行アクセラレーター
Converts the surviving plan into a staged roadmap, priorities, MVP definition and a frame a real team can run Monday morning.
The SOP — strict order
Gap Diagnosis 市場空白スキャン
All six personas blind-read the input in parallel. Output: the three largest market/user/business gaps, and the three most fatal assumptions or blind spots.
3 gaps3 fatal assumptions
Stress & Build Debate 対抗型構築
Architect proposes → Commander layers the business logic → Slayer and Empathy Engineer attack in rounds. The plan must answer: why would a user pay money or time, and why is now the window?
propose → layer → attack
Empathy Refinement 共感リファインと検証
Real user stories, behavioural paths and emotional touchpoints get injected — moving the plan from "correct" to "wanted".
correct → wanted
Delivery & Metrics Lock 実行と指標ロック
North Star Metric + key sub-metrics, staged roadmap (MVP → v1.0), resource needs and risk mitigation — then the human makes the call. The mode sharpens the decision; it never makes it.
NSM + roadmaphuman go/no-go
Binding constraints
No transition filler, no template sentences — the language of a strong product lead in a working meeting.
Every recommendation links to a concrete outcome — ARR, retention delta, cycle time, CAC — and every figure is labelled estimate or measured. An unlabelled number is a violation.
No differentiation, no real gap → the personas say so plainly. "This direction dies at the starting line" is a legitimate finding, not rudeness.
Every output answers one question before any other: which whitespace does this build a moat in?
Honest scope. The personas are lenses, not credentials — "top-tier researcher calibre" describes the standard the output is held to, not who is talking. Numbers are estimates until measured, and the mode labels which is which. It critiques directions, not people; regulated domains route through counsel; and the go/no-go stays human. Download the mode, load it into any capable agent, and pair it with the when the plan reaches the screen.
Start · AI-native
A real session: Claude × this system.
This is what working in Claude (Cowork) with these contracts connected actually looks like — the brief, the tool calls, the moment a hard rule pushes back, and the human signing the result. Step through it: every payload shown is the shape the real files return.
Hook it up — three doors, same contracts
Add the MCP server to your config (the eds-mcp production pattern — a cds server is the same shape), or simply tell Claude to read the contracts by URL: no install, works in any chat.
One line registers the server for the whole project; CLAUDE.md or AGENTS.md makes the contracts binding for every session that follows.
The session, step by step
A real working session, replayed in-page. The same loop runs in any MCP-capable agent.
Start · Production evidence
The design file and the code agree.
This catalogue argues that a component is only real once it is written down in a form both a person and a machine can check. That argument is easy to make on a page you control. So here it is on something else: one Button out of the production component library I work in, read twice — once from the Figma inspector, once from the machine-readable specification the shipped implementation was serialised into. Same numbers, same enums. Nothing below asks to be believed; it asks to be compared.
One component, read twice
Buttonvariant: outlinedsize:
xlargecolor: infostate: defaultH 60"height": 6024"padding": "12px 24px"12"padding": "12px 24px"8"gap": 8full pill"borderRadius": 30 → height /
2Four dropdowns, four enums
The variant panel on the left of that screenshot is not decoration. Each dropdown is a prop, and its options are that prop’s declared value list — same members, same order, same default.
containedoutlinedtextdefault
containedxsmallsmallmediumlargexlargedefault
medium
primaryerrorsuccesswarninginfogreydefault
primary
The fourth one deliberately does not match. Figma shows state
as an enum because a designer needs default, hover, disabled and loading laid out side by side. In code they
arrive as independent props — disabled and isLoading — because a button can be both.
That is a translation, and it is written down as one. Drift is when a difference is undocumented, not when it
exists.
The same shape, one layer down
Button is the worked example because both halves of it can be shown. The discipline is not local to it. One
shared size enum — xsmall / small / medium — is the sizing contract
for 12 form entry points, and each rung fixes a total height rather than leaving it to
whoever draws the frame.
24"4px 8px" · radius 432"8px 8px" · radius 440"8px 16px" · radius 8spacing(n) = n × 8px, and a Button’s radius
is derived from its height rather than chosen.
How it stays true — the loop
Build the component in Figma
As a variant set, not a stack of frames: every prop that exists in code exists as a Figma property, so the two can be compared at all.
variant set = prop set
Write the rules down before the components
Which size for which context, what each semantic colour means, the spacing rule, the radius rule — in prose a person and an agent read the same way, so neither has to infer intent from pixels.
rules → then components
Serialise the whole thing
Design tokens, prop enums, pixel specifications and the guidance around them become one machine-readable file. The point is that "what this component is" stops living in someone’s memory and starts living somewhere a diff can be taken against it.
one file, both audiences
Update under authorization
When something needs to change, the Figma MCP connection and the agent assemble the change against that file. It lands only after a person approves it. The loop is allowed to propose; it is not allowed to merge.
agent proposeshuman authorizes
Described as workflow, not as a result. No cycle-time figure, no percentage, no before-and-after appears above, because none has been measured. What is shown is the shape of the process and one component that came out of it matching.
What this is and is not evidence of. It is evidence that a component’s numbers can be checked against a written contract instead of eyeballed, and that on this one they hold. It is not a claim of authorship over the library: the specification is derived from the shipped implementation, so it documents code that already existed — the work being shown is making that code legible enough that design and implementation can be held to each other. Coverage is partial and stated as such: of its 53 component entries, 15 carry hard pixel specifications; the rest fix props and behaviour and leave layout to the consumer. And the source file, the package it belongs to and its version are not published here — the figures under comparison are the point, and the file is not mine to hand out.
Start · Provenance
Who builds a 190-category system solo?
The same person who ships the institutional one. This page is the range proof; the production record is the depth proof. Every claim below links to its evidence — the discipline of this catalogue is that nothing asks to be taken on faith, including its author.
Self-audited, not self-described: node cds/verify.mjs
last ran against this exact file and returned 4,058
assertions passed, 0 failed — page↔contract parity, every anchor present, bundles and hard
rules valid, all 119 skills enumerated, and the token-contrast table recomputed from raw hex. Anyone can
re-run it: node cds/verify.mjs https://edwson.com.
And read, not just parsed: node cds/smoke.mjs executes this page’s
own scripts against a hand-written DOM, activates all 201 sidebar entries, and dispatches a
click on every one of the 975 interactive controls — twice each, because a state
machine that only works once is the failure a single click never finds. It then checks
keyboard parity: every widget role on a div is clicked, snapshotted, reset, and
given Enter and Space, and any control that moves under a mouse and not under a keyboard is named. Last run:
0 runtime errors, 0 keyboard-parity failures. There is no browser and no network on the
machine that runs it, which is the point — the DOM is 419 lines and the
harness has no dependencies.
The evidence trail
every row links to the artifact itselfThe Institutional Finance Design System — 251 component categories for trading, compliance, and AML, each with a regulatory anchor. This consumer system is its B2C sibling: same four-cell register, different rulebook.
Nearly five years at an ASIC-regulated broker — a 150-component system across five platforms that absorbed 8 regulatory rewrites without a rebuild cycle; KYC completion 27→55% (GA4, Q2–Q3 2022).
eds-mcp — the institutional system shipped as a real MCP server: 29 tools, 65 contracts across 14 domains (plus this consumer catalogue since v1.17.0), zero-dependency HTTP API with an OpenAPI 3.1 spec, tests green. The pattern this page's machine layer is built to.
Ed Agent — a human-gated agent harness (v0.6.2): nine lifecycle stages, red-team + claim grounding, iron-law hard-halts, a deterministic skill router over a 139-method library, 15 MCP tools. The operating belief behind this page's agent demo: agents produce, the harness governs.
ReactOmega (51 AI-native React components, shadcn-compatible, with its own MCP server) and GalaxyJS (60 canvas animations, zero dependencies) — the playful end of the same systems rigor.
10 signed LinkedIn recommendations — Managing Director to teammates, publicly verifiable, quoted in full. “Ed’s implementation of a centralized design system was a game-changer for our team’s output” — Jim Kao, Frontend Engineer (SDE II), same team.
Why a second system, not a footnote on the first — the institutional one exists because a regulator can ask why a screen looks the way it does, and I need the answer on file. I built this one to find out whether that same discipline holds up somewhere no regulator is watching, whether the rigor was ever really about finance or just about writing the reason down. It held.
This catalogue is new — first published July 2026 — but its patterns already run in the founder's own live consumer products (Duo-Shou, PawsRoam, WizAgents). The numbers above are the institutional and open-source track record whose discipline it inherits.
Glassmorphic
Liquid Glass Surface
Three surface treatments built to Apple’s Liquid Glass material logic — and rebuilt from the blend model up, because the CSS published for that look does not render it. Drag the panel across the wallpaper: the readout is the white label’s contrast against the backdrop under it, and it travels from 16.4 : 1 to 1.1 : 1 without one property of the component changing.
Chrome that floats over the user’s own content or wallpaper — a media player, a camera control, a home-screen widget — where you want the surface to admit what is behind it rather than hide it. Works only when the backdrop is something you control or can measure.
Never as a substrate for text you have not scrimmed. Two measurements, both taken here: the
backdrop under this panel ranges 1.11 : 1 to 16.41 : 1
across one wallpaper, and the composited glass itself, rendered in Chromium and read back at five
positions, ranges 1.25 : 1 to 7.51 : 1 — so the surface
narrows the range and never rescues it. Never inside an
ancestor that isolates or flattens — isolation, transform,
filter, will-change, opacity below 1, or a
z-index on anything positioned, each collapse it to a
near-black slab, so fading one in destroys it for the length of the fade. z-index is on
that list because it collapsed four of the five components below during this build — stacking one glass
element above another is the obvious thing to reach for, and it is the thing that breaks it. Never
more than a couple
per view: blur(20px) is a full-surface GPU pass.
The panel is a real focusable control: arrow keys move it 12 px (48 with Shift), and the readout is
an aria-live="polite" region so a screen-reader user gets the same contrast verdict a sighted
one reads. Where backdrop-filter is unsupported the whole layer stack is dropped for an opaque
panel — degrading to legible, not to decorative.
WCAG 2.2 · 1.4.3 contrast minimum — the clause this technique is most often used to break.
Apple HIG materials & vibrancy; CSS Backdrops & Filter Effects
(backdrop-filter); CSS Compositing 2 (mix-blend-mode,
plus-lighter). The design language is Apple’s and public; this implementation of it, and
the contrast governance
around it, are not derived from any shipped code.
Every combination, measured. White text on the composited surface, rendered in Chromium and read back from the pixels — the three recipes against the three zones of this wallpaper. Only three of the nine clear 4.5 : 1, and the two that clear it comfortably are the ones where the wallpaper was already dark. That is the argument for the five components below: the recipe is not what makes the text legible.
Ratios against white. pass clears 4.5 : 1 for body text, large only clears 3 : 1 but not body, fail clears neither. Spelled out as well as coloured, because a table that encoded its verdict in hue alone would fail the clause it is reporting on.
What the copied CSS does not do. Figma’s “copy as CSS”
flattens this into one element with background-blend-mode. Rendered over this same wallpaper
that is a near-black slab: background-blend-mode blends an element’s own
background layers against each other and nothing else, and the effect depends on blending with the page
behind it. The layers have to be real children with mix-blend-mode, and the
backdrop-filter has to sit on the topmost one — on the container the stack paints opaque
over its own blur.
glass
isolate
translateZ(0)
0.999
Four identical panels. The three on the right sit inside an ancestor that forms its own stacking or blending context, which is all it takes.
Glassmorphic
Backdrop Contrast Guard
A translucent surface cannot promise a contrast ratio, because it does not own its backdrop. This is the mechanism that lets you ship one anyway: measure what is behind the panel, and when it will not hold the text, put a substrate under the text instead of hoping.
Any glass surface carrying text over content you do not control — user wallpaper, a photo, a video frame, a map. Also the honest answer to “can we use the glass style here?”: yes, if it is guarded.
Not a substitute for choosing a legible design — a guard that fires on most of the screen is telling you the surface is wrong for the content, not that it needs a bigger scrim. Do not sample on every animation frame; sample on settle. And do not let the guard flip repeatedly while dragging: a label that strobes between glass and scrim is worse than either.
The decision and the measured ratio are both exposed as text in a polite live region, so the guard is auditable rather than magic. The scrim is a real opaque layer behind the text, not a lowered text opacity. Threshold is 4.5 : 1 for body text and it is a floor, not a target; hysteresis stops the flip from oscillating on the boundary.
WCAG 2.2 · 1.4.3 (4.5 : 1 normal, 3 : 1 large) and 1.4.11 non-text contrast; WCAG 2.2 · 4.1.3 status messages for the live verdict. Apple HIG legibility guidance for materials. The ratio is computed with the WCAG relative-luminance formula, not eyeballed.
With the guard off, the label over the pale cyan measures about 1.2 : 1 — white on near-white. The guard does not tint the glass or fade the text; it puts an opaque pill behind the words, because that is the only thing that actually changes the ratio.
Glassmorphic
Glass Sheet
A bottom sheet that shows the context it interrupts. The glass is the reason it feels attached to the screen underneath; the scrim is the reason it is still readable and still a modal.
A short, focused decision that benefits from keeping its context visible — share, sort, a quick confirm. The translucency earns its place when the thing behind is what the decision is about.
Never without the scrim: on glass alone the sheet stops being modal, and the text sits on whatever happened to be underneath. Not for long forms — if it scrolls, it is a screen. Not for destructive confirms where the wording must be unmissable; that gets an opaque dialog.
role="dialog" with aria-modal="true"; focus moves to the sheet on open and
returns to the trigger on close; Tab is contained while it is open and Escape closes it. The scrim is
clickable and does the same thing as Cancel. Body copy sits on its own opaque panel, so the readable part
never depends on the backdrop. Reduced motion drops the slide.
WAI-ARIA APG dialog (modal) pattern; WCAG 2.2 · 2.1.2 no keyboard trap (a modal is the sanctioned exception — Escape must work), 2.4.3 focus order, 1.4.3 contrast, 2.3.3 animation from interactions. Apple HIG sheets; Material 3 bottom sheets.
Share “Spaces”
The heading and body sit on their own opaque panel. The glass is the frame; it is not the substrate for the words.
Glassmorphic
Glass Segmented Control
The capsule picker this whole domain is steered with. On glass, the selected segment has to be an opaque fill — a translucent “selected” state is a state you cannot see against a backdrop you do not own.
Two to four mutually exclusive views of the same content, where switching is cheap and instant — a filter, a density, a chart range. On a glass surface it keeps chrome to one row.
Never for actions — a segment is a choice, a button does a thing. Not past four segments or with labels that wrap; that is a select. And never signal the selection with opacity or tint on glass: over a pale backdrop a translucent selected pill and an unselected one look identical.
role="radiogroup" with role="radio" and aria-checked — a
radiogroup, not a tablist, because it filters content rather than swapping panels. Arrow keys move the
selection, Home and End jump to the ends, and only the selected segment is in the tab order. Selection is
carried by an opaque fill and a mark, so it survives greyscale.
WAI-ARIA APG radio group pattern; WCAG 2.2 · 1.4.1 use of colour, 2.5.8 target size, 2.1.1 keyboard, 4.1.2 name role value. Apple HIG segmented controls; Material 3 segmented buttons.
A dark veil, and a metric that was measuring the wrong thing. White labels here measured 1.30 : 1, so the track needs a floor. A white frost was used first, on the grounds that the dark veil keeps only 0.10–0.16 of the backdrop’s luminance span where ink on frost keeps 0.47–0.70. Both numbers are right and the conclusion was wrong: luminance span is not what makes a surface read as glass — hue is. Rendered side by side, the dark veil keeps 140% of the wallpaper’s chroma and 0.40 of its structure where the frost kept 64% and 0.17, and the frost went milky. So the veil is dark, the labels are white, and the selected segment is an opaque white chip — unambiguous against a dark track anywhere on the wallpaper, which is exactly what the cell above asks for.
Glassmorphic
Glass Notification
The worst case for this material and the most common use of it: a banner over a wallpaper nobody designed. It cannot know what is behind it, so it carries its own substrate and stops asking.
Transient, non-blocking feedback over a lock screen, home screen, or full-bleed media — where an opaque bar would feel like a system error and the glass reads as part of the surface.
Never for anything the user must act on, and never for errors that need a decision — a toast that disappears is not a place to put consequences. Never rely on the glass for legibility: the backdrop is a photograph the user chose. Never auto-dismiss faster than the text can be read, and never at all while it has focus or the pointer is on it.
A polite live region — announced without stealing focus. Content sits on its own opaque inner panel, so the ratio is a property of the component and not of the wallpaper. Dismiss is a real 44 px button, not a swipe-only gesture; hover, focus, and reduced motion all pause or remove the timer.
WCAG 2.2 · 4.1.3 status messages, 2.2.1 timing adjustable, 1.4.3 contrast, 2.5.8 target size, 2.1.1 keyboard (a gesture always needs a button beside it). Apple HIG notifications; Material 3 snackbars.
The stage is parked on the palest part of the wallpaper on purpose. With the inner substrate off, the white text measures 1.42 : 1 — read back from the composited pixels, not estimated — and that is the default state of most glass notifications in the wild.
Start · Changelog
Changelog
Versioned like software, because it is software. Historical entries are never edited — only appended.
- Kindness-First & Anti-Dark Patterns Growth Manifesto. Added the flagship
.cds-kindness-bannerdirectly into Overview, formalising four humane design pillars: Streaks with Grace Days (psychological safety & cognitive relief), FTC 1-Click Honest Cancellation (zero retention mazes or dark nudge gymnastics), Transparent Truth in Pricing (full upfront pricing without drip tricks), and Sensorial Calm (reduced-motion compliance and breathing whitespace). - Omnipresent Keyboard Shortcuts & Parity. Added instant search focus with ⌘K / Ctrl+K and uncluttered / trigger across desktop and tablet surfaces, paired with instant clear and dismissal via Esc.
- Verification Contract Regenerated. Synchronised all machine-readable contract layers: 190 component categories, 17 domains, 44 dual-theme WCAG 2.2 AA contrast pairs, and 0 smoke test errors across 146 rendered pages.
- Every check in this repository read the page as text. None of them ran it. A
handler bound to a selector nothing matches, a demo that reads a property off
null, a toggle that works once and breaks on the second press — none of those are visible to a parser, and all of them are visible to a visitor within about four seconds. cds/smoke.mjsexecutes the page. It parses the document intocds/domshim.mjs— 335 lines of DOM: selector matching, event delegation with bubbling,classList,innerHTMLre-parse, and the globals the demos touch — evaluates all ten inline scripts, activates all 201 sidebar entries, and dispatches a click on every one of the 975 interactive controls. Twice each, because a state machine that only works once is the failure a single click never finds.- Keyboard parity is asserted, not assumed. This catalogue cites WCAG 2.1.1 in dozens
of entries. The test for it is not “is there a keydown listener somewhere” — it is
whether what a mouse can do, a keyboard can also do. So every widget role sitting on a
divis clicked, snapshotted, reset, and given Enter and Space; anything that moves under a mouse and not under a keyboard is reported by name, and a widget role with notabindexis reported as unreachable. - Result on this build: 0 runtime errors, 0 keyboard-parity failures across 975 controls and 13 non-native widgets. That is the first time this page has been able to say that about its own behaviour rather than about its own markup.
- Both guards were negative-tested by breaking them. One character changed in a
handler’s root selector — caught, named to the inline script. One
tabindexremoved from a spatial card — caught, named to the section and the element. There is no browser and no network on the machine that runs this, which is the constraint the harness was written to, not a limitation it works around.
- The contrast table was stale, and the sentence above it said it could not be. The
preamble claims every ratio is computed from
tokens.jsonand re-asserted bycds/verify.mjs. It was not: the JSON was recomputed and checked, the rendered table was not, and eight of its eighteen printed cells were pre-v1.18.0 values. Every stale figure was lower than the truth, so the page under-sold its own tokens — a smaller error than over-claiming and exactly the same failure of the claim. The table is now emitted fromtokens.jsonbycds/emit-contrast-table.mjs, shows all 44 pairs per theme rather than nine, and every cell is bound to the contract in both directions. - Twelve motion tokens were documented and did not exist. The Motion section
published twelve “canonical” primitives with MCP payloads labelled as served from
cds/tokens.json. None of the twelve was in that file. None was in the page’s own CSS either — the demos hardcoded the same curve values as literals, in the one section arguing that a value belongs to a token. They are now declared, consumed throughvar(), captured by the generator, and asserted: a token the page advertises must be shipped, and a token that is shipped must be used by something. - The generator was reading one
:rootblock out of eight. The page declares tokens in more than one place, and the token capture only ever saw the first. Eleven live tokens — the five motion roles with their eases, and--csp-floor— never reached the contract, while the page named--csp-flooras one of three tokens a re-brand may not repoint. An agent could not enforce a rule about a token it never received. The count moved from 42 to 65 per theme; none of the new ones is new work, all of them were already on the page. - Twenty citations were wrong. Found by checking every anchor against its primary
source rather than re-reading them. The most consequential: this page cited the FTC
“click-to-cancel” rule as binding in two places, and the Eighth Circuit vacated
it in full on 8 July 2025, days before its compliance date — what actually governs is
ROSCA. Also:
465.4is buying reviews, suppression is465.7; GDPR Art 6 is lawfulness, purpose limitation is Art 5(1)(b); the 2.2.2 exception is five seconds, not a cycle count;aria-grabbedwas removed from ARIA 1.2 and is implemented by nothing; data tables, banners and steppers are Material 2 components that Material 3 never documented. - The page failed three criteria it cites in dozens of entries. An
aria-controlspointing at an id nothing carried — inside the tree-table demo whose own cell reads “expand state is announced, not just drawn”; four controls whose only name was a placeholder; anh2 → h4skip. All fixed, andcds/verify.mjsnow checks every IDREF resolves, every control has a name that is not a placeholder, and no heading level skips. - An anchor is now required to cite something. Sixty-nine anchors named a body with
no rule behind it — “community-safety conventions” — under the same heading as
the ones naming GDPR. Rather than add a softer label, which would let the soft ones keep borrowing the
authority of the hard ones, the generator extracts what each anchor actually cites, publishes it as
anchorCites, and refuses to build an anchor that cites nothing. - Fifty-four raw hex values were painting the page. Forty-five of them in the glass
and media clusters — the sections whose whole argument is that a value belongs to a token. The
exemption is real (a material that follows
--bgstops being a material); what was missing was a boundary. Thirteen compositing constants are now named —--on-media,--media-*,--glass-rim,--verdict-*— and the exemption ends there: zero opaque hex in a paint property outside the token layer, asserted.rgba()survives, because a scrim over arbitrary content is an alpha value rather than a colour choice. - Assertions 3,038 → 4,054. Every new guard was negative-tested by breaking the thing it protects: a reverted contrast cell, a dropped token, an advertised token nothing uses, a dangling IDREF, a removed label, a heading skip, an anchor stripped of its citation, a re-introduced hex, a stale entry count in both directions. Nine breaks, nine failures, all caught.
- v1.35.0 made this contract worse for every model that runs on someone’s own hardware. Putting the full decision register on all 190 entries took the index from 172 KB to 296 KB — about 76K tokens, which is the entire window of most locally-run models. A better contract that a local model cannot open is not a better contract.
- Four smaller tiers, written by the same generator run.
cds/RULES.txt(4.2 KB — the protocol, all seven hard rules, all seven bundles, the non-negotiables, small enough to paste as a system prompt);cds/tokens.json(19.3 KB, unchanged);cds/domains/<domain>.json— 17 shards, 6.1 to 44.8 KB, the full register for one domain only; andcds/index.slim.json(54.1 KB) for choosing rather than building. Rules + tokens + one shard is 7.6K tokens at the smallest domain and 17.5K at the largest, and it is complete — nothing is fetched at build time. - Nothing here is an API. No server, no key, no schema compiler, no embedding index.
Fetch once, commit the files beside your code, and the contract — including
node cds/verify.mjs— keeps working with the network off. - The tiers are asserted against each other, not trusted.
cds/verify.mjsnow requires the 17 shards to hold 190 components between them, the slim index to list the same ids in the same order and at the same version, every shard entry to carry a full register, and the rules card to contain every hard rule by id. The first version of that last check passed a card withclick-to-canceldeleted, because the phrase also appears inside a bundle reason — the negative test caught it and the check now matches[id]. Assertions 3,024 → 3,035.
- The when-not-to cell is now in the contract, not only on the page. This section has
said for six versions that the when-not-to cell is binding. It was binding for a human reading
the register and unenforceable for an agent reading JSON, because
components.jsoncarried only id, name, domain, summary, anchor and URL. Every entry now ships its whole decision register —whenToUse,whenNot,a11y,anchor— extracted by the generator from the page’s own cells, never hand-written, and the generator exits non-zero if a section is missing one. 190 of 190 carry a full register; the index is 172 KB → 295 KB and an agent no longer has to parse HTML to build compliantly. - The MCP surface is reproducible instead of asserted.
components.jsongained anmcpblock withtoolsToFileMapping— which slice of which file each tool reads — plusworksWithoutAServer, because every tool here is a way of slicing two static files. It also states plainly that there is no separate cds-mcp package and why one has not been written. A newfetchGuidanceblock tells a fetching agent the cheap path, thatwhenNotis a refusal condition rather than advice, and that if this file and the page disagree the page wins. - Re-branding is now a documented, provable operation. A new
Make it yours block names the eight tokens that actually carry brand against
the thirty-four that carry structure, and shows the loop that makes it safe: the generator reads the
tokens back out of the page, recomputes all 44 contrast pairs per theme from your hex values, and
refuses to write the file if any drops below 4.5:1. It also names the three tokens a
re-brand may not repoint —
--red,--greenand the--csp-flooropacity — because they carry meaning that components’ when-not-to cells depend on. - Two places still said “142 entries”. Again. The v1.32.0 entry below
records fixing exactly this, and it came back, because the number moves every release and nothing
referred back to it.
cds/verify.mjsnow scans live prose for any entry count above the contract count — excluding this changelog, whose historical numbers are correct as written — and hard-pins the two sentences that speak for the whole index. Assertions 3,019 → 3,024.
- A new domain for the layer below the interface. The catalogue already carried
mobile-shaped patterns — pull to refresh, bottom sheets, tab bars. What it did not carry was the
set of conditions a phone imposes on any of them: a screen that is not the rectangle you were given, a
keyboard that takes a third of it, a process the system can end without warning, a battery mode that
revokes autoplay. New domain
mobile: safe area and insets, keyboard avoidance, edge-swipe back, thumb reach, Dynamic Type, lifecycle and state restoration, low power and data saver, orientation and foldables, live activity, deep link and cold start. - Every entry demonstrates the failure, not only the fix. Each demo has a control that turns the contract off — ignore the insets and Compose sits under the home indicator, drop avoidance and the composer hides behind 132px of keyboard, disable restoration and a cold start returns an empty step 1. A specimen that only ever shows the correct state does not teach anything; the argument for the rule is what happens without it.
- Anchored to platform rules, as the rest of the catalogue is. The ten platform anchors cite Apple HIG (layout, onscreen keyboards, gestures, Dynamic Type, Live Activities, Universal Links), Material 3 and Android (window insets, predictive back, window size classes, App Links, battery saver), W3C drafts actually in use (CSS Environment Variables, VisualViewport, Device Posture, Page Visibility, Network Information) and eleven distinct WCAG 2.2 success criteria — including 2.4.11 focus not obscured and 2.5.7 dragging movements, both of which exist because of exactly these conditions.
- Contract v1.34.0 — 190 entries across 17 domains, every one anchored.
cds/components.jsonandcds/tokens.jsonwere regenerated from the page rather than hand-edited; the self-referential assertion count moved 2,908 → 3,019 as the new sections brought their own checks with them.
- Six components built to a platform material language. The three surface
treatments follow Apple’s Liquid Glass logic (iOS 26), the same way the rest of this catalogue is
built to Apple HIG and Material 3; the layer values were cross-checked against a public Figma Community
reference rather than guessed at. The implementation is not that reference — applied as published
it does not render the effect at all, so the surface was rebuilt from the blend model up. New domain
glass: draggable surface comparison, contrast guard, floating tab bar, bottom sheet, segmented control, notification. - The copied CSS does not reproduce the design. Figma’s
“copy as CSS” flattens the stack into one element with
background-blend-mode. Rendered over the same wallpaper in Chromium that is a near-black slab, becausebackground-blend-modecomposites an element’s own background layers against each other and nothing else. The effect needsmix-blend-modeon real children, and thebackdrop-filterhas to sit on the topmost blended layer — on the container the stack paints over the blur and the blur is never seen. All four arrangements were rendered and compared before one was chosen. - Nine measurements instead of an adjective. White text on the composited surface, read back from the pixels: three recipes × three zones of the wallpaper. Three of the nine clear 4.5 : 1, and the two that clear it comfortably are the ones where the wallpaper was already dark. The matrix is on the page, with the verdict spelled out as well as coloured.
- The floor is a dark veil, and the metric that argued against it was measuring the wrong
thing. Words on glass need a floor: white text needs 4.5 : 1, the lightest region
of these wallpapers reads 1.11 : 1 for white, so the composite has to land at or below
119/255 — a near-black veil at alpha 0.56. A white frost was built first instead,
because the dark veil keeps only 0.10–0.16 of the backdrop’s luminance span where ink on a
0.46
frost keeps 0.47–0.70. Both figures are correct; the conclusion was not. Luminance span is not what
makes a surface read as glass — hue is. Rendered side by side over the same wallpapers the dark veil
keeps 140% of the wallpaper’s chroma and 0.40 of its structure,
against 64% and 0.17 for the frost, which went milky and read as grey
plastic. Adding
saturate()to thebackdrop-filtermoved chroma retention by 1–4 points, because the veil sits above the blur and is the thing that desaturates. So:--cgl-veilwith white labels,--cgl-scrimwhere a dark substrate is the point, and an opaque white chip for the selected item — unambiguous against a dark track anywhere on the wallpaper, which a translucent pill can never be. - The three recipes are not interchangeable, and two stages were parked on flat ground. The floating bar rendered grey on a coloured wallpaper: sampled against the wallpaper beside it, recipes 1 and 2 keep 14% of its chroma there and recipe 3 keeps 64%, so the bar uses recipe 3. Separately, the segmented control was sitting on a patch with a luminance spread of 0.035 when 0.28 was available a few percent away — a blur of a smooth gradient is a smooth gradient, and glass needs an edge behind it to be visible at all. Both stages moved, and the segmented one lost a third of its height: 874×382 around a 232×36 control was 97% empty photograph.
- The control moved under the pointer. The selection mark was rendered only on
the selected segment, which made it ~14px wider than its neighbours — measured three different
segment layouts for three selections, so the thing you were about to click shifted as you arrowed
through. The mark now reserves its space on every segment and is revealed rather than inserted: one
layout, always. The segments are also equal width now (they were 62 / 92 / 90 — three different
target sizes for three equivalent choices), the track has 4px of padding so the selected chip sits
inside it rather than flush against its edge, and the focus ring moved inside the chip in the
label’s own colour: at the default
outline-offset: 2pxit exactly filled the track’s gutter and collided with the track edge. Because the label colour is already solved against what is behind it, the ring is guaranteed visible on both the ink-on-white chip and the white-on-dark segments. - The recipe does not scale. Its inset rim is specified in absolute pixels — 16px, 12px and 2px offsets with a 22px inner glow — and was authored for a 32px-radius panel. On a 44px-tall pill those offsets span the whole element. Small surfaces carry the same rim re-specified at roughly a third.
- Centring by hard-coded width. Avoiding the stacking-context trap, the bar was centred
with
margin-left:-110px— half of a width that is actually 200px, so it sat 10px off-centre. The individualtranslateproperty does not form a stacking context wheretransformdoes, so it centres itself now and measures 0.0px off. - Four of the six broke the way the domain says it breaks. A
z-indexon a positioned element forms a stacking context, which isolates the blend and collapses the surface. The tab bar, sheet, segmented control and notification were all stacked that way first and all four rendered as slabs. They stack by DOM order now, and the tab bar is centred withmargin-leftbecausetransformforms a context where the individualtranslateproperty does not.cds/verify.mjsnow asserts this instead of trusting it: both guards were tested by reintroducing the defect and watching them fail. - Five tokens were borrowed from the wrong design system.
--gold,--r-xs,--text-xs,--weight-semiboldand--weight-boldexist on the institutional showcase, not here, so every declaration using them was being dropped and falling back to inherited values. Translated to this page’s vocabulary (--amber, the*-softtints, literal sizes and weights). - Two ARIA faults the markup argued with itself about. The bottom bar carried
role="tablist"while its active item carriedaria-current="page"— tab vocabulary and navigation vocabulary in one element, andtablistforbids plain buttons. It isrole="navigation". Its scroller had also reused anaria-labelthat an existing component already owned, leaving tworegionlandmarks indistinguishable. axe-core reports 0 violations in both themes. - Contract
cds/components.json— 180 components across 16 domains, every one carrying a platform anchor. The self-test runs 2,908 assertions.
- The count was wrong, so the count changed. Four pairs of entries were the same
component written twice — and two of those pairs shared an element
id, sosec-datepickerandsec-uploadeach existed on the page twice and the second sidebar row for each silently scrolled to the first one. The catalogue holds 174 distinct categories, not 178. Date & Time Picker, Upload & Camera, Multi-Step Form and Coach Mark each absorbed the better half of their twin rather than discarding it: all four now carry two previews — a typed field and a range grid, a single upload and a per-file queue, a dot rail and a named-step list, an anchored tip and a floating-action tip — and the unique rules from both registers. Nothing was deleted except the duplication. - “Generated from the page so it can never drift” had no generator behind it.
It was a description of intent, and the index had drifted: two duplicate ids, a count four too high, and
24 entry summaries that no longer matched the prose on the page.
cds/generate.mjsnow derivescomponents.jsonandtokens.jsonfrom the page's own sidebar and:rootblocks, refuses to write if an id repeats or a bundle points at nothing, and answers--checkin CI. The sentence is now executable. - The contrast table was measuring the easy surfaces. It held nine pairs per theme and
every one sat on
--bgor--surface. The page paints text on--surface2,--surface3and five tinted*-softpanels constantly, and there eight tokens sat between 3.22:1 and 4.44:1 — an axe-core pass over all 174 sections in both themes returned 1,506 contrast failures against a page that prints “AA” as a headline statistic. Nine tokens were re-solved at constant hue and saturation until every surface cleared 4.5:1, a--red-fgtoken was added because white on the dark theme's red measured 2.82:1, and the table went from 9 pairs per theme to 44 — every pair the page actually renders. The tokens moved; the claim did not. - Zero axe-core violations, both themes, all 174 sections — including
best-practice rules. Calendar grids now carry the row and column-header structure
role="grid"requires (viadisplay:contents, so the semantics cost nothing visually);aria-expandedmoved off a table row and onto the disclosure button that owns it; links inside prose are underlined rather than signalled by hue alone; the star-rating targets are declared at 28 px instead of inheriting whatever an icon font happened to load at. - 25 entries promised copyable code and did not carry any. They had a live preview and
no code block at all, against a page — and a JSON-LD
abstract— that says every entry carries one. All 25 now do, each with the rule the markup exists to enforce. - The self-test passed 1,180 assertions over every one of those defects. It read
section ids into a
Set, which deduplicates precisely the fault it was looking for.cds/verify.mjsnow runs 2,656 assertions and asserts on raw lists: id uniqueness, sidebar uniqueness, contract → sidebar reachability, four decision cells and a code block per entry, one version string across the header and every JSON-LD block, and every size claim in prose, meta and the no-JavaScript hero fallbacks against the computed count. Run against v1.31.0 it reports 82 failures. Every assertion in it exists because a real defect got past the previous version. - Also: the hero read “fourteen domains” beside a stat tile reading 15; the no-JavaScript
fallbacks — what a crawler without a JS engine actually reads — said 170 / 110 / 12; two
JSON-LD blocks declared v1.30.0; two places still said “142 entries”; the Agent Library
section had no sidebar row and was reachable only by typing its hash; and one block styled dark mode
with
@media (prefers-color-scheme: dark), so it ignored this page's own theme toggle.
- A section whose evidence is not self-issued. Everything else here is a system checking itself. takes one Button out of a production component library and reads it twice — once from the Figma inspector, once from the machine-readable specification the shipped implementation was serialised into — on five numbers that either match or do not: height 60, horizontal padding 24, vertical padding 12, gap 8, radius derived as height/2. Width is excluded, in writing, because the frame hugs its content and the specification states none.
- The enums are the same object twice. Three Figma variant dropdowns are the prop value
lists member-for-member. The fourth,
state, deliberately is not — code splits it into independentdisabledandisLoadingprops — and that translation is documented rather than smoothed over. Drift is an undocumented difference, not a difference. - Workflow stated as workflow. The four-step loop (Figma variant set → written rules → serialised specification → agent-prepared updates over Figma MCP that merge only after a human authorizes) carries no cycle-time figure and no percentage, because none has been measured. The section also names what it does not prove: the specification is derived from shipped code rather than authored ahead of it, and 15 of its 53 entries carry hard pixel specifications.
- Contract v1.31.0 — component count unchanged at 178; the new section is
provenance, not a catalogue entry.
cds/verify.mjsnow runs 1,180 assertions.
- A fifteenth domain, and the first one about time rather than about a widget. Eight entries — Motion Role Tokens, Focus Zoom, Attenuated Context, Anchored Control, Draw to Create, Elevation on Commit, Shortcut-Teaching Menu, Stack Gather — covering direct manipulation and the motion that makes it legible. Every one carries the same four-cell register as the rest of the catalogue, and every one is anchored: WCAG 2.2 §2.5.7 Dragging Movements and §2.1.4 Character Key Shortcuts do most of the work here, alongside §1.4.13, §2.4.11 and §2.3.3.
- Motion typed by role, not by size. The existing
--dur-1/2/3scale answers “how big is this element”. Five new tokens answer “what is this movement for” — Navigation, Ambient, Reveal, Commit, Settle — and every one collapses to 1 ms underprefers-reduced-motionat the token, so no component can forget. The two scales coexist; the older one was never wrong, it was answering a different question. - Two rules the domain refuses to bend. Attenuated content is
inertandaria-hiddenfor as long as it is attenuated — visually present is not programmatically present. And no creation, reorder or grouping gesture ships as a drag alone; the single-pointer path sits beside it at equal visual weight, because a secondary accessible path is a path a team eventually stops maintaining. - Contract v1.30.0 — 178 entries across 15 domains, every one anchored.
cds/verify.mjspasses unchanged.
- Two local-model agent methods. A Local Tool-Use Router (ReAct + a validated API interceptor so an open-weight model can trigger Python, DB queries and webhooks — allowlisted, schema-checked, human-gated on the irreversible) and a Dynamic LoRA Router (intent-classified hot-swap of task-specific adapters with a confidence threshold and a base-model fallback). The Skills Kit is now 119 methods.
- Honest by construction. The router “proposes; the harness disposes” — irreversible tool calls stop for a human; and the LoRA method ships an adapter only if it beats the base model, reports measured switch latency rather than claiming “instant,” and frames adapters as task-shaped depth, not a claim of frontier general intelligence.
- Eleven corporate-legal & engineering methods. Six for Business & Strategy — commercial & technology contracts, IP strategy & licensing, secured transactions & creditors’ rights, antitrust & competition law, a corporate compliance & ESG program, and corporate governance & M&A defense; plus five for Product Tools — DevOps & CI/CD, formal methods & QA, requirements engineering & scoping, distributed-systems architecture, and AI for code. The Skills Kit is now 117 methods across six categories.
- Deduped, and honest about the line. Thirteen requested topics consolidated to eleven (contract-drafting merged with contracting-for-technologists; two IP topics into one). Every legal method states plainly that it is not legal advice and routes the determination to counsel; per se antitrust conduct is refused, not structured around; and the engineering methods keep the “model produces, the human governs” discipline with a human on every irreversible step.
- Eight marketing & market-expansion methods. A quantitative-growth cluster joins the kit — Python data science, statistical modeling, ML for business, and NLP/sentiment (Product Tools); plus marketing analytics science (CLV, attribution, churn, dynamic pricing), behavioral economics, brand positioning, and market research & intelligence (Business & Strategy). The Skills Kit is now 106 methods across six categories.
- Deduped by construction. Eleven requested topics consolidated to eight distinct skills: predictive-analytics folded into ML + marketing analytics, customer-centricity into market research, and go-to-market was already covered by the existing GTM skill. Each new method keeps the kit’s honesty contract — a “what this is NOT” boundary, estimates labelled, and manipulation, covert data, and unsubstantiated claims routed to their guardrails.
- The export keeps up with the kit by itself. With the Skills Kit now at 98 methods across six categories, the AI-Ready panel’s counts are read live from the contract: the skill-method picker shows a per-category count on every chip (and a running total on All), and the “what’s inside” manifest and its caption inject their numbers from the same source — so they can never drift stale again the way the old hard-coded “39” did.
- Contract drift caught and fixed.
components.jsonstill declared 160 categories while its own array held 170 (the data & tables and product & metrics domains had been added without updating the count); the domain list was missing two entries and the anchored-entry count lagged. All three are regenerated from the array — 170 categories, 14 domains, 170 carrying a platform anchor — so the machine layer matches the page.
- Five skills for team scaling, org health, and a legacy-code audit. Employer branding & talent engineering (competitor talent flow from public signals + gameable-resistant interviews), cross-border workforce cost optimization (fully-loaded cost across two scales and geographies with hire ROI), org-health & retention guard, and a cultural-friction & retention guard join Business & Strategy; a long-context legacy codebase audit (a local model ingests 100K–300K tokens to find zombie code, breaking-upgrade risk, and design debt, proposing low-blast-radius refactor PRs) joins Product Tools.
- The people skills carry the kit’s strongest privacy framing: attrition and burnout signals are aggregate, consented, and team-level — never covert surveillance of named individuals; per-person monitoring and scoring raise privacy, consent, and legal issues and route to HR and counsel; market comp is a public-source estimate, not a rival’s actuals; talent-flow reads use public signals only; and the codebase audit auto-applies nothing — every refactor is a reviewed, tested PR merged by a human. Component count unchanged at 160.
- Eighteen skills for the full product loop. Product-conflict analysis & PRD writing, backend-data growth with GEO/SEO, a blog copy AI-tone humanizer, GitHub OSS discovery with a license audit, analytics event taxonomy, agile Epic & BDD tickets, and an autonomous A/B-testing engine join Product Tools; competitive analysis, global GTM, R&D cost accounting, high-net-worth client relationship (private-banking lens), game-theory counter-strategy, crisis-PR war room, and a consultant-grade MECE/7S strategy blueprint join Business & Strategy; user-journey friction mapping, an ethical dark-pattern audit, a WCAG 2.1 AA & i18n guard, and design-tokens & component-state expansion join Research & Craft.
- Same honesty rules: not affiliated with or endorsed by any named firm (UBS, McKinsey) — their frameworks are a reference lens, not their brand; competitor DAU/MAU and download figures are labelled public or inferred estimates, never a rival’s actuals; SEO/GEO carries no ranking guarantee and no black-hat tactics; behavioral tagging is consented and privacy-respecting; and every legal, financial, security, and compliance decision routes to a qualified professional. Component count unchanged at 160.
- Organizational Memory Architect — the kit’s flagship method. Decision archaeology for a company: the agent reads what the org already has (tickets, epics, reports, project chat, version history, UAT and release records) and reconstructs the decisions and constraints — every claim cited to its source, every rationale labelled documented or inferred, veterans confirm before inference hardens into history. Output is role-scoped: PM, engineering and design briefs plus onboarding packs calibrated to the newcomer’s position and background. The method opens at the security gate (InfoSec scope and exclusions before the first fetch) and closes with a maintenance cadence — because a snapshot of institutional memory starts rotting the day it ships. The organizational generalisation of the single-designer onboarding protocol documented in the institutional showcase.
- The head-level skills ItemList was regenerated from the contract — it had drifted to 53 while the kit grew to 75. Caught, fixed, and the drift is recorded here rather than papered over.
- A fourteenth domain: Product & Metrics. Five metric surfaces — DAU/MAU KPI cards that name their comparison window, a Stickiness Ratio that prints its definition of "active" (change the definition and the same product tells a different story — the definition is the metric), a retention cohort grid where unknown cells are em dashes rather than estimates, an activation funnel whose percentage base is part of the claim, and an annotated metric chart where the list of causes is the accessible record. Five roadmap surfaces — Now/Next/Later with no dates on Later, a confidence timeline (solid = committed, hatched = planned, outline = exploring — pattern + word, never colour alone), an append-only public changelog with rollback entries, a feature-request board where declining honestly beats ghosting, and a staged-rollout status whose opt-out survives every expansion.
- All ten carry live deterministic demos. Contract v1.17.0 — 170 entries, every one anchored.
- Five design-industry health diagnostics. Two design/UX maturity reads join Research & Craft: InVision-lens design-maturity assessment (is design decoration or business strategy?) and NN/g-lens UX-maturity assessment (research process, design-system upkeep, quality control). Three agency-business health reads join Business & Strategy: Promethean-lens agency operations (time-tracking data, scope-creep, pricing structure), AMI-lens operational leverage (billable utilization against the ~60–70% range, overhead ratio, margin per biller), and Bureau of Digital-lens peer benchmarking (compensation, rates, margins against real peers).
- Same honesty rules: not affiliated with or endorsed by any of these organizations, their published frameworks used as a reference lens and proprietary benchmark data not reproduced; utilization and benchmark figures cited as labelled industry rules of thumb, never precise facts about a specific studio; nothing audited, and compensation, pricing, and people decisions routed to the owner and qualified advisors.
- Component count is unchanged at 160 — skills are a meta layer.
- Six signature enterprise-health diagnostics. Each firm’s best-known organizational-health lens, distinct from its existing skill: McKinsey organizational health (OHI & 7S — alignment, execution, renewal), Bain customer & founder’s-mentality health (NPS plus front-line vitality, catching “big-company disease”), PwC / Strategy& capabilities-driven strategy & Fit for Growth (does spend match the capabilities the strategy needs), Deloitte technology & operations health via process mining (bottlenecks and cash leaks in ERP and supply chain), EY transformation & resilience health (readiness for geopolitical, tech, and regulatory shock), and KPMG risk & compliance controls health (three-lines-of-defense control maturity).
- Same honesty rules as the rest of Business & Strategy: not affiliated with or endorsed by any firm, the publicly understood framework used as a reference lens and proprietary instruments (the actual OHI questionnaire, benchmark databases) not reproduced; every score labelled an informed estimate; nothing audited or certified; and legal, compliance, cyber, HR, and financial judgments routed to qualified specialists and counsel.
- All six join the Business & Strategy category in the filter and the AI-Ready Export. Component count is unchanged at 160 — skills are a meta layer.
- Ten business-analysis skills, and a sixth category to hold them. Enterprise finance, operations, risk, and market methods written in the analytical lens each firm is known for — McKinsey operations & value drivers, Deloitte enterprise health score (syncing spend, people, market, and product vitality into one transparent score), PwC P&L & EBITDA review, KPMG multi-lens risk, EY revenue forecast & FP&A, Moody’s financial-health & credit-risk grading, S&P market position & share, and Coupa enterprise spend analysis — plus two firm-agnostic methods: AI displacement risk and a product-logic adversarial review (steelman, red-team, data audit, pre-mortem).
- Honesty is load-bearing here: every firm skill states it is not affiliated with or endorsed by the firm and uses the publicly understood analytical discipline as a reference lens, not their brand or proprietary methodology; every figure is labelled measured or estimated; nothing is audited, and financial, tax, legal, or investment decisions route to licensed professionals. The Moody’s method issues an internal analytical opinion, explicitly never a real credit rating.
- New sixth filter category Business & Strategy in both the filter and the AI-Ready Export. Component count is unchanged at 160 — skills are a meta layer.
- A thirteenth domain: Data & Tables. Ten entries for the surfaces where consumer products handle structure — Tree View (ARIA tree, four-arrow keyboard walk), Selection Tree (honest tri-state parents), Tree Table (rollups computed from children so parent and breakdown can never disagree), Editable Cells (Enter commits, Escape restores, errors explain in place), Table Pagination (exact ranges, honestly disabled ends), Column Manager (hide ink, never data), CSV Export (GDPR Art. 20 portability — the click states its row count), Table States (four truths, one frame, zero CLS), Sparkline Cells (an honest baseline by default — the cropped axis is a labelled toggle, because a chart is a claim), and Comparison Table (sticky column, glyph + word marks that survive grayscale).
- All ten are live interactive demos, delegated vanilla JS, dual-theme by token, reduced-motion aware. The contract (cds/components.json v1.13.0) grew to 160 entries — every one carrying an anchor.
- The contract is now self-testing.
cds/verify.mjs(zero-dependency, Node 18+) runs 849 assertions — page ↔ index parity, anchors, bundles, skills, agent protocol — locally or against the live site. And the WCAG citations now carry their own evidence: an 18-measurement token-contrast table (both themes) lives in tokens.json and on the page. Its first run failed — light hint text measured 2.49:1 — so the tokens were fixed, not the claim.
- Five skills for bots, product, data and digital wallets. Telegram and Discord bot development — from surface design to intents, rate limits, localization and a deployment architected for growth; a Notion thinking assistant that structures reasoning and drafts while the human keeps the decision; a Digital Wallet architecture method; and Datadog observability that a person or agent can operate on the team’s behalf.
- The wallet skill ships with the strongest honesty framing in the kit: it is a design-and-architecture method with security humility, not a security guarantee — no rolling your own crypto, no claim of what-you-see-is-what-you-sign on a compromised host, and a professional audit and counsel required before real value moves. The bot and Datadog skills keep secrets out of code and gate destructive or billing-impacting actions behind a human.
- Both the filter and the AI-Ready Export pick them up: the two bots join Agents & Coding, Notion / wallets / Datadog join Product Tools. Component count is unchanged at 150 — skills are a meta layer.
- Nine skills for product, design, backend and data. A SEO & GEO self-audit method (drawn from strengthening this site’s own machine layer: fold out your own traffic, split bots from humans, then lift both search ranking and AI-answer discoverability); three design-system adoption methods that decide fit before adopting and then keep the whole system on-rails without drift — Material Design, Ant Design, Apple HIG; and five product/backend/data tools — Google Analytics (GA4), Trello, Confluence, MySQL, and Databricks.
- Same discipline as the rest of the kit: each is a bounded working method, not official docs and not affiliated with any vendor, with every irreversible action (a production DROP, a destructive data op) and every privacy or regulated decision routed through a human. The backend and data skills make the backup-first, human-gated rule explicit.
- Both the category filter and the AI-Ready Export pick them up: the three design-system methods join Research & Craft, the six tool methods join Product Tools. Component count is unchanged at 150 — skills are a meta layer.
- The Design.md pack now carries the skill methods. A skill-method picker (All / None /
five categories) compiles the matching skills from the live
components.json.skillsindex into the pack — name, description and downloadable .md URL, grouped by category. The export used to ship 150 components but ignored the 39 skills; now the pack is the whole toolbox, not half of it. - Three more target tools: Codex (AGENTS.md +
~/.codex/config.toml), Antigravity IDE (workspace rules + MCP), and Opencode (AGENTS.md +opencode.json) — each with an accurate setup snippet for theedsMCP server. Seven targets in all. - A "what the pack contains" manifest makes the depth legible at a glance, and the compile stat now reports components and skills separately. Still deterministic, still client-side, still no model.
- Search & sort on the Skills Kit. A search box filters the 39 skills by tool, task or domain; a sort control offers featured order (restored from the original DOM order, captured once), A–Z, and Z–A; a live count and an empty state complete it. Document-delegated, keyboard-accessible, token-themed for both modes.
- Six new skills. NotebookLM Source Curation (assemble authority-scored primary sources for a domain before grounding), NVIDIA CUDA GPU Optimization (size rendering + VRAM to the real hardware, verified fully on-GPU), Graphic Design Award Research (verify winners against the official archive; dissect the design logic that won), Awwwards Site Analysis and FWA Award Analysis (design vs build difficulty rated separately ★1–5, inferred stack flagged as inference, 3–5 competitor sites anchored to your project), and Design System Analysis — Ed Chen's objective lens: no hype, no hate, facts and judgments labelled separately, anchored to the user's actual goal.
- Same honesty spine as the rest of the kit: working methods, not official docs, not affiliated; award
and difficulty ratings labelled as estimates; every winner verified against the primary source; no
cloning of awarded work. Skills remain a meta layer — the component count stays 150;
components.jsonships all 39 in itsskillsindex.
- Nine tool-specific skills covering the full product-development loop, one per tool the agents already run: AWS (IaC + least-privilege IAM + cost guardrails + gated destroys), Firebase (security rules first, Emulator-tested, App Check, cost-aware), GitHub (PR-first, CI as the merge gate, protected main, SHA-pinned Actions), Google Jules (async-agent delegation + a QA-automation planner that turns edge cases into a committed test suite), Jira (acceptance criteria, capacity-honest sprints, human-owned status), Slack (specific alerts, self-assembling incident channels, in-channel approvals gated on a human click), VS Code (an agent cockpit with MCP wired to a real contract), Cloudflare (edge deploy with previews, tested WAF, DNS changes gated because they go global in seconds), and Perplexity (cited research you follow to the primary source and verify before shipping).
- Each squeezes the tool for maximum leverage and keeps the same spine as the rest of the kit: a working method, not official docs, not affiliated — and every irreversible action (deploy, delete, DNS, IAM, prod data, money) and every regulated domain routes through a human, the way the AI & Agents domain already argues.
- Skills are a meta layer, not catalogue entries — the component count stays 150.
- Eight tool-specific skills, one per AI tool in the strip above. Two built to request: an n8n method that turns the automation tool into a standing test harness (scheduled smoke tests, schema assertions, loud alerts, workflow JSON in version control), and an Ollama method that deploys via Docker and recommends the model your GPU can actually run — a VRAM-first sizing heuristic (params × quant + KV overhead) with a pick per memory tier. Then one each for Hermes Agent (open-weight reasoning core, typed tools, human-gated loop), OpenClaw (computer-use agent operated safely — allowlists, no credentials, injection-aware), Monica (a trustworthy general-assistant workflow), OpenCode and Cline (terminal and VS Code coding agents — plan before edit, tests as the gate, MCP wired to a real contract), and Hugging Face (card before weights, licence before commercial use, pin the revision, prefer safetensors).
- Each carries the same honest frame as the rest of the kit: a working method, not official docs, not affiliated — and every one routes irreversible actions and regulated domains through a human, the way the AI & Agents domain already argues.
- Skills are a meta layer, not catalogue entries — the component count stays 150.
- Eight of the most-used, most-often-botched components, done properly: a sortable
data table (real
<table>semantics,aria-sortshown by glyph not hue, a genuine indeterminate “select all”); a dropdown menu that is a list of actions, not a select in disguise (ARIA menu pattern, roving focus, Esc restores the trigger); a command palette (⌘K) built as a combobox witharia-activedescendant; a tooltip that explains but never contains; copy to clipboard that awaits the promise and never fakes a green tick; a rating input that is an accessible radiogroup, not clickable decoration; a tag input where every token is individually removable and announced; and relative time that keeps the exact, timezone-correct value one hover away. - Every one ships the four-cell decision register with a real platform anchor (WAI-ARIA patterns, WCAG 2.2 — 1.3.1, 1.4.1, 1.4.13, 4.1.3), a live demo, and copyable code. All 150 entries now carry an anchor.
- Counts stay derived from the live navigation — hero, domain map, and
cds/components.json(regenerated to v1.8.0) all read 150 without a number being typed by hand.
- New: Design Agent Mode — an adversarial six-persona operating mode (Market Gap Hunter, Product Architect, Business Logic Commander, Risk & Feasibility Slayer, Empathy & Validation Engineer, Delivery & Momentum Accelerator) with a strict four-step SOP: gap diagnosis → stress & build debate → empathy refinement → delivery & metrics lock, ending at a human go/no-go.
- Binding constraints ship with it: zero AI-voice, everything quantified with estimate-vs-measured labels, zero tolerance for mediocrity, gap first. Downloadable as design-agent-mode.md — honest framing inside: personas are lenses, not credentials; the mode sharpens the decision, never makes it.
- Skills Kit grew 10 → 16: Product Design Kit (tokenize any product surface into a Design Kit document with a mandatory Known Gaps section), Dify Workflow Planner (LLM-app logic before nodes: three-lane graphs, per-node model routing, human gates), ComfyUI Pipeline Architect (graphs as pipelines: pinned seeds, VRAM budgets, versioned workflow JSON, license checks), Generative Image Direction and Generative Video Direction (briefs over slot machines, with binding honesty rules — synthetic never masquerades as evidence, disclosure per EU AI Act Art 50), and AI Asset Integration (provenance intake, C2PA that survives the CDN, versioning like code).
- Tool skills state their independence plainly: not affiliated with Dify or ComfyUI — the platforms change; the planning discipline is what transfers.
- Skills Kit: ten downloadable, CDS-native Markdown skills for designers and developers — Screen Composer, Component Author, Design Review, Dark-Pattern Audit, Accessibility Verification, UX Writing, Motion Choreography, Token & Theming, Framework Port, AI Surface Kit. Each references the machine contracts directly, so method and machine layer can't disagree; legal-adjacent skills route to counsel by construction. The institutional sibling keeps its 40 general skills; these ten are the catalogue's specialists.
- AI-Ready Export: compile a Design.md pack client-side from the live contracts — pick a target tool (Claude Code / Claude Desktop / Cursor / any agent) and domains, get the agent protocol, hard rules, bundles, component index and dual-theme tokens in one copyable, downloadable file. Deterministic, no model involved; the Design.md packaging idea popularised by tools like Alpy Studio, implemented here from a live versioned system.
- New twelfth domain: Text Animations — ten original, zero-dependency motion components in vanilla CSS/JS: Split Reveal, Blur In, Typewriter, Decode, Count Up, Word Rotate, Gradient Flow, Shine Sweep, Wave, and Marquee Ticker. The category landscape is popularised by React libraries (ReactBits and company; the author's own ReactOmega ships the React take) — these are the component-form siblings, token-bound and contract-carrying.
- Every entry ships the discipline the genre usually skips: real text in the accessible name with animation aria-hidden (screen readers hear one sentence, never letter soup), reserved layout space (zero CLS), self-terminating loops (rotate and wave stop by construction, the marquee ships a visible pause control per WCAG 2.2.2), and reduced-motion renders the final state instantly.
- Live demos autoplay once on view via IntersectionObserver, with a Replay control per preview; Count Up carries the FTC note that motion is emphasis and emphasised claims need evidence.
- Social grew 8 → 14: Profile Header (stats are links), Message Inbox (Requests folder — consent applies to attention), Poll & Voting (results only after you vote), Mentions & Hashtags (entities, not text), Live Stream Chat (never steals your scroll), Link Preview Card (the domain is the security surface).
- Core grew to 37 with the universal gaps: Date & Time Picker (native first, grid for ranges), File & Photo Upload (per-file lifecycle, retry), Multi-Step Flow (Back is free), Stats & Sparkline Card (honest baselines), Coach Marks (one tip, never a tour), Address Form (autocomplete is a shortcut, not a gate), Appearance Switcher (drives this page's real theme), Language & Region (self-named, never flagged).
- Iconography rebuilt as a governed library — 155 glyphs across 16 semantic categories (navigation, actions, communication, commerce, media, status, trust, system, AI & agents, files, time, health, travel, food, home & devices, weather & environment), each with use/never rules, plus the four selection rules: filled = selected, sizes are stops, RTL mirrors direction not meaning, and the label test. components.json regenerated — 132 entries, all with anchors; eds-mcp consumer pack snapshot refreshed in lock-step.
- New: "Claude × CDS Session" — a step-through reconstruction of a real working session in Claude (Cowork): brief → index fetch with agentProtocol → bundle enforcement → live artifact → a growth request that hits the click-to-cancel hard rule and gets refused with a citation → compliant alternative → human signs. Honest framing: deterministic replay, no model called, no affiliation implied.
- Setup made concrete: config snippets for Claude Desktop / Cowork (MCP server or zero-install read-the-AGENTS.md-URL) and Claude Code (claude mcp add + a binding CLAUDE.md line).
- Machine Layer section now routes to both live demos — watch the session, then run the builds.
- AI & Agents grew 14 → 22: Tool & Data Grants (one revocable grant per capability, logged to the trace), Background Agent Tasks (queued / working / needs-you / done, cancel keeps partials), Mode & Model Picker (outcomes not parameter counts, price at the decision point), Ghost Text & Suggested Edits (never auto-commits), Human ↔ Agent Handoff (who's driving, delta recap on resume), Usage & Cost Meter (the cap disclosed before the cap), Generated Artifact Card (versions + provenance + C2PA export), Capability Disclosure (the anti-magic card).
- components.json regenerated: 118 entries, all with anchors; bundles gained agent-confirm→agent-trace and agent-grants→agent-trace — an approval without an audit trail is theatre.
- Four new live demos: background task with a needs-you gate state, ghost-text accept/dismiss, handoff take-over with delta recap, credit meter with the 80% announcement.
- The read path: a seven-step rail documenting exactly how an agent consumes this system — discover → fetch index → select → read register → resolve bundles & hard rules → build from tokens → gate to a human.
- The reading logic is now machine-carried: components.json ships agentProtocol, bundles, and hardRules alongside the 110 entries, so an agent that fetches the index receives its own instructions with the data.
- MCP console grew from four to seven tools: find_by_anchor (regulation-first discovery), get_bundles (bundled-by-contract pairs), diff_since (sync the delta, not the world).
- A new domain: AI & Agents (14 entries). Composer, streaming response, sources & citations, confidence & abstention, AI disclosure with C2PA content credentials, agent action confirmation, agent activity trace, prompt starters, feedback & correction, memory & context, training vs personalisation controls, AI summary in search, refusal & human escalation, voice agent. The through-line is the one the institutional sibling already argues: the model produces, the human signs — a gate authorises an exact payload, never a plan; a trace records what was blocked, not just what worked; abstention is a feature; and a refusal with no door is just a door closing on someone who came to you for help.
- Six gaps closed where the catalogue was thin: date & time picker, upload & camera, multi-step form, coach mark, subscription management, and account deletion — the last because App Store Review 5.1.1(v) makes in-app deletion a requirement, not a courtesy. A system you can only join is not one anyone should trust.
- The anchors are real and checkable: EU AI Act Art. 50 (transparency), Art. 14 (human
oversight), Art. 12 (logging); GDPR Art. 7, 16, 17, 21, 22; NIST AI RMF; C2PA 2.x; FTC negative-option
and substantiation rules; WCAG 2.2 — including 4.1.3, which is why the streaming region is
aria-live="off"and the finished answer is announced once. Streaming a token at a time into a polite live region makes an answer less accessible than a spinner would have been. - Counts everywhere — hero, domain map,
cds/components.json— are still derived from the live navigation. Nothing in this release was a number typed by hand.
- Machine layer strengthened: head-level JSON discovery links + Dataset structured data; AI-tool strip and a "Connect it" panel (direct fetch today, MCP via the eds-mcp production pattern) with copyable config; downloadable AGENTS.md drop-in brief for any agent.
- New: "Build with an Agent" — a deterministic in-page simulation of an agent assembling four briefs from the catalogue, including a COPPA hard-block, against the real component index.
- New: "Who Built This" — provenance section linking every capability claim to its artifact (institutional showcase, eds-mcp, Ed Agent, OSS, signed recommendations).
- Chrome: portfolio link moved to the top-right and sidebar footer.
- 90 component categories across 10 domains — foundations, core, navigation, onboarding & identity, commerce, social, media, growth & engagement, trust & safety, patterns.
- Every entry ships the four-cell decision register with a platform anchor (HIG, Material 3, WCAG 2.2, App Store / Play policy, GDPR, COPPA, FTC), a live tokenised preview, and copyable vanilla code.
- Machine layer: cds/tokens.json + cds/components.json, generated deterministically from this page's navigation; illustrative MCP console shows the tool-call shape.
- Dual theme (light default, dark), spring motion gated behind prefers-reduced-motion, 44px touch targets, WCAG 2.2 AA contrast baseline.
Foundations
Color
A near-neutral canvas with one working accent. Consumer color earns attention it doesn't demand: semantic colors mean the same thing on every screen, and no state is ever encoded by hue alone.
Accent for the one primary action per view and for selected states. Semantic green/red/amber only for outcome, danger, and caution. Everything else stays neutral so content owns the saturation.
Never use red for emphasis — it is reserved for destructive and error meaning. Never encode a state by color alone; pair with an icon, weight, or label (streaks, unread, live all double-encode here).
Text tokens hold ≥ 4.5:1 against their surfaces in both themes; large text and icons ≥ 3:1. Both themes ship from the same token names — components never reference a raw hex.
WCAG 2.2 · 1.4.3 contrast (minimum) and 1.4.1 use of color; HIG Color (semantic, adaptive colors); Material 3 color roles.
Neutrals & text
Accent & semantics
Foundations
Typography
Two voices: a tight display face for moments, the native system stack for everything else. Consumer type is generous — bigger minimums, looser leading, tighter tracking as size grows.
Display face (Inter Tight, −0.03em and tighter) only for hero and section moments. Body is the system stack at 16px minimum — it renders instantly, matches the OS, and never needs a font download to be readable.
No display face below 20px — tight tracking collapses at small sizes. Never justify body text, never letter-space lowercase body copy, never ship text in images.
All sizes in rem so user font-size preferences scale the whole system; layouts survive 200% zoom (WCAG 1.4.4) and reflow at 320px (1.4.10). Numerals in prices and counters are tabular.
HIG Typography (Dynamic Type); Material 3 type scale; WCAG 2.2 · 1.4.4 resize text, 1.4.10 reflow, 1.4.12 text spacing.
Interactive specimen
The scale
Foundations
Spacing & Layout
A 4px base grid with an 8-step scale. White space is the cheapest premium material there is — this system spends it deliberately.
Scale steps only — 4, 8, 12, 16, 24, 32, 48, 64. Related things sit one step apart, unrelated things two. Section rhythm comes from consistent vertical steps, not from dividers.
No off-scale values to "make it fit" — if a layout needs 13px, the layout is wrong. Don't add dividers and spacing; pick one separator per level.
Interactive targets are at least 24×24 CSS px (WCAG 2.5.8); where a visual is smaller, the spacing exception applies — a 24px circle centred on it must not intersect another target's circle, which is a centre-to-centre rule, not a clear-gap one. List rows pad to a 44px minimum touch height.
HIG Layout (44pt targets, safe areas); Material 3 4dp grid; WCAG 2.2 · 2.5.8 target size (minimum).
Foundations
Materials & Elevation
Three levels of shadow and one glass. Elevation answers exactly one question — what is above what — so it is spent like money.
Level 1 for resting cards, level 2 for raised or hovering elements, level 3 only for overlays that float above the page (sheets, toasts, menus). Glass for chrome that must show content scrolling beneath it.
Glass never carries body text over unknown content without a contrast fallback. No stacked glass — one translucent layer per screen region, or blur costs melt low-end phones.
Every glass surface declares a solid fallback color for browsers without backdrop-filter, and text on it still meets 4.5:1 against the worst-case underlying content in the fallback.
HIG Materials (vibrancy, translucency); Material 3 elevation; WCAG 2.2 · 1.4.3 contrast over variable backgrounds.
Blur + saturation lifts the layer; the hairline sells the edge. Content stays the painting — this is just the frame.
Foundations
Motion
One spring, three durations. Motion in this system is spatial reasoning — it tells you where things came from and where they went. Anything that only decorates gets cut.
Enter/exit of overlays, state changes the user caused, and continuity between views. The spring — cubic-bezier(0.32, 0.72, 0, 1) — is shared by everything, so the product feels like one object.
No ambient looping animation near reading content. No motion longer than 480ms on the critical path — the user came to do something, not to watch the interface perform.
prefers-reduced-motion is a contract: transitions collapse to opacity or nothing, parallax and auto-playing movement stop. Nothing flashes more than three times per second, ever.
WCAG 2.2 · 2.3.3 animation from interactions, 2.3.1 flash thresholds; HIG Motion; Material 3 motion (emphasized easing).
12 Canonical Motion Tokens Click any tile to
trigger its real-time spring curve, or inspect its MCP tool response payload serving
cds/tokens.json.
State Feedback Snap
Tactile press response with elastic recoil snap. Shared by buttons, toggles, and chip selections.
Spatial Layout Morph
Pill expands into expanded metadata card. Maintains spatial continuity across views.
Sheet & Overlay Settle
Bottom sheet slide-up with spring damping & backdrop blur fade. "The house spring".
Magnetic Hover Affordance
Tile follows cursor within magnetic pull radius with inertia recoil upon release.
Accordion & Panel Unfold
Height auto-fit expansion with staggered opacity reveal for nested content.
Radial Liquid Ripple
Click anywhere inside tile to emit expanding translucent liquid wave from cursor coordinates.
Skeleton & Loading Shimmer
Shimmering gradient light beam scanning across loading skeleton placeholders.
Toast & Notification Pop
Notification pill pops up with overshoot spring & auto-dismiss timer bar.
Staggered List Cascade
Items cascade into view sequentially with 60ms staggered delays and slide-up fade.
Glass Specular Highlight
Diagonal specular light ray glints across dark glassmorphic card on hover/trigger.
3D Perspective Flip
Card flips 180 degrees in 3D perspective to reveal machine MCP JSON payload.
{"mcp": "ok"}Reduced Motion Contract
Instant collapse to zero spatial movement & 180ms opacity crossfade under prefers-reduced-motion.
Foundations
Iconography
Icons are labels that got shorter, not decoration that got meaning. One family, one optical grid, and a text label whenever the action is destructive or unfamiliar.
Recognition-level concepts only — search, share, settings, play. Filled variants mark selected state against outlined resting state (the tab bar pattern).
Icon-only buttons for irreversible actions are forbidden — "delete" gets a word. Never invent a metaphor a first-time user must decode; if it needs a tooltip to be understood, it needs a label instead.
Every functional icon carries an accessible name (aria-label or visually-hidden text); decorative icons carry aria-hidden. Minimum functional icon target: 44px including padding.
HIG SF Symbols conventions (weight-matched, filled-selected); Material Symbols; WCAG 2.2 · 1.1.1 non-text content.
How to choose — the four rules
Selection logic
155 glyphs · 16 semantic categories · one optical gridOutlined is the resting state, filled is the active one — the tab-bar convention. Never mix weights inside one surface; the eye reads weight as meaning.
16px inline with text, 20px in list cells, 24px in bars and buttons, 28px+ only as feature art. Functional icons keep a 44px touch target regardless of glyph size.
Back/forward, chevrons, and send mirror in right-to-left locales. Checkmarks, playback, clocks, and brands never mirror — physics and convention don't flip.
If a first-time user needs a tooltip to decode the glyph, it needs a visible label instead. Destructive, irreversible, and money-moving actions always carry the word.
Use Getting around. Directional glyphs mirror in RTL; position is a promise — back lives top-left forever.
Never A chevron discloses within a place; an arrow moves you to another one. Swapping them breaks the user's map. Close (×) dismisses without saving — never use it to mean done.
Use Verbs the user performs on things. Every glyph here changes state — so every one must be undoable or confirmed.
Never Destructive actions (trash) are never icon-only — 'Delete' gets the word. Undo/redo arrows are never decoration. Send commits: don't reuse the paper plane for anything reversible.
Use People talking to people. These glyphs carry badges — which makes them attention surfaces with a budget.
Never The bell is for things that happened, never for marketing (see Badge & Count). The share glyph follows the platform — iOS and Android draw it differently; don't invent a third.
Use Where glyphs meet wallets. Everything here appears near a price, so precision beats charm.
Never Pick bag or cart once and never mix them — they are the same concept wearing two coats. Currency symbols are locale, not decoration: $ is not universal, and the receipt glyph never decorates marketing.
Use Fifty years of convention. Playback glyphs are the closest thing interface design has to traffic signs.
Never Never restyle play/pause into brand shapes — recognition is the entire value. CC is a first-class control, not a settings burial. The camera glyph means capture now, not photos-the-noun (that's image).
Use The system talking back. Each of these is one third of a triple encoding: icon + word + color, always together.
Never Semantic glyphs are never decorative — a checkmark that doesn't mean success is a lie in vector form. The spinner means short waits only; anything longer earns a progress bar and a cancel.
Use The glyphs users bet on. A lock is a claim about the world, so it renders only when the claim is true.
Never Never use the padlock as marketing garnish — it means this, here, is actually protected. Eye/eye-slash toggle visibility states honestly. The fingerprint never implies biometrics leave the device.
Use The machine's own furniture: preferences, connectivity, locale, accessibility.
Never OS status glyphs (signal, battery) belong to the OS — faking system UI inside an app is a trust violation. The globe means web or region by context; pair it with a label so it never has to mean both at once.
Use Marking where the machine is. These glyphs are disclosure surfaces — their presence is a claim about who or what produced something.
Never Sparkles mean AI-generated or AI-powered, here, truthfully — never sprinkle them on ordinary features to look modern (that's the capability-overclaim FTC cares about). The robot renders only when a bot is actually speaking.
Use Things users keep. The folder is a place, the file is a thing, the paperclip attaches — three metaphors older than the web, still load-bearing.
Never Format glyphs (PDF) appear only when the format changes what the user can do with it. Print exists wherever a document does — receipts and tickets especially. Archive means retrievable; if it's actually delete, use delete.
Use When things happen. Calendar glyphs distinguish looking (days), adding (plus), and confirmed (check) — three different promises.
Never History (the rewinding clock) is the user's own data trail — wherever it appears, a way to clear it must exist nearby (GDPR Art 17 adjacency). Recurring (repeat) on anything billable is a subscription disclosure, not decoration.
Use The body's dashboard. Everything in this row marks special-category data — the glyph itself signals sensitivity.
Never Health glyphs flag GDPR Art 9 territory: where they appear, consent and controls follow. Never gamify the medical (streaks on medication adherence need clinical judgment, not growth instincts), and the flame never pressures eating behaviour.
Use Modes and destinations. Transport glyphs are choices with prices — they sit next to money, so they carry the precision discipline of commerce.
Never The passport marks identity-document territory: wherever it appears, treat the flow like KYC, not like a form. Mode glyphs never editorialise — the bicycle isn't 'eco' unless the claim is substantiated (see Weather & environment).
Use Appetite at a glance. Category glyphs help scanning; dietary glyphs are safety information wearing a small coat.
Never Dietary markers (plant-based leaf, gluten wheat) are accuracy claims with allergy consequences — they render from verified data only, never from vibes. The scooter means live delivery tracking, not a marketing promise of speed.
Use The connected household. Every glyph here mirrors a physical device's state — the interface is a remote control for reality.
Never IoT state must be verified state: a lock glyph showing 'locked' from a stale cache is a safety lie, not a rendering bug. Show last-updated time when confidence is stale, and never render a camera glyph as recording when it isn't — or vice versa.
Use The outside world, and claims about caring for it.
Never Eco glyphs (leaf, seedling, recycle) are regulated marketing claims — the FTC Green Guides apply to a green leaf on a checkout as much as to an ad. 'Eco delivery' with no substantiation is greenwashing at 16 pixels.
Honest scope. The glyphs on this page render in Font Awesome as a preview stand-in; in a shipped product each platform uses its native family (SF Symbols, Material Symbols) at matching optical weight. The contract this catalogue defines is the semantics and the limits — which glyph means what, where it may appear, and what it must never be used to imply — not the vendor of the vectors.
Foundations
Haptics & Sound
The invisible foundation. A web page can't fire a Taptic Engine, so this entry is the policy layer: when native surfaces of the same product should speak through touch and sound, and when they must stay silent.
Haptics confirm what the eye might miss: a toggle landing, a pull-to-refresh arming, a payment succeeding. Sound is rarer still — reserved for messages arriving and capture moments.
Never haptic on scroll, on every keystroke, or to celebrate the app itself. Duplicate meaning, don't invent it — a buzz with no visible counterpart is noise with extra steps.
All haptic and audio feedback is redundant to a visible change — deaf and haptic-off users lose texture, never information. System silent-mode is always respected.
HIG Playing haptics ("use haptics consistently, don't overuse"); Material guidance on haptic feedback; WCAG 2.2 · 1.3.3 sensory characteristics and 1.4.1 use of colour — instruction may not depend on a single sense. (There is no “1.1 redundancy principle”: 1.1 is Text Alternatives.)
Core · Control
Button
The pill is the promise: one obvious next step per view. Everything else steps down in weight until hierarchy does the persuading, not color.
Actions — buy, send, save, continue. One primary per view region; secondary and ghost carry everything else. Full-width primaries live at the thumb edge on mobile.
Navigation is a link, not a button. Danger styling is for destructive actions only — never for urgency theatre ("Buy now before it's gone" does not get to be red).
44px minimum height. Loading sets aria-busy and disables the control — a double-tap on "Place order" is a duplicate charge. Focus ring is restyled, never removed.
HIG Buttons (prominence hierarchy, 44pt targets); Material 3 button hierarchy; WCAG 2.2 · 2.5.8 target size, 2.4.7 focus visible.
Core · Form
Text Input
Labels stay visible, errors say what to do next, and the keyboard that appears is the one the field deserves. Most abandoned checkouts die in a form.
Free-form single-line entry with a permanent label above and helper text below. The right inputmode and autocomplete attributes are part of the component, not an optimisation.
Placeholder-as-label fails the moment typing starts. If the answer is one of five things, use a select or segmented control — don't make thumbs spell what a tap can choose.
Error text is tied via aria-describedby and never conveyed by border color alone. Fields never clear on error. Labels are real <label> elements — tapping them focuses the field.
WCAG 2.2 · 3.3.1 error identification, 3.3.2 labels, 3.3.7 redundant entry, 1.3.5 identify input purpose (autocomplete); HIG Text fields.
Core · Form
Search Field
The front door of every catalog, feed, and library. Rounded, iconed, instant — and it never punishes an empty result with a dead end.
Whenever the collection exceeds what one screen can browse. Results update as-you-type where the corpus allows; recent searches fill the empty field's dropdown.
Don't ship search as an apology for bad navigation on a five-item menu. Never hide the only path to content behind an icon-only collapsed search on desktop.
type="search" with a visible clear affordance; role and results count announced to screen readers via a live region ("14 results"). Zero results always offers a next move.
HIG Search fields; Material 3 search; WCAG 2.2 · 4.1.3 status messages (result counts).
Core · Form
Select
The native picker wearing the system's clothes. On phones the OS wheel and sheet pickers beat anything a div can fake — so this select stays a <select>.
Five to fifteen mutually exclusive options. Below five, use a segmented control or radios so all choices are visible; above fifteen, use search-in-a-sheet.
Never for two options (that's a toggle or radio pair), never for navigation, and never a custom-div dropdown when the native element would do — you inherit a decade of OS accessibility for free.
Keyboard type-ahead, arrow navigation, and screen-reader announcement come from the native element and are never re-implemented worse. The label is external and permanent.
HIG Pickers; Material 3 menus; WCAG 2.2 · 4.1.2 name-role-value (free with native semantics).
Core · Control
Slider
For values where the feel matters more than the digits — volume, brightness, price range. The current value is always readable, never guessed from thumb position.
Continuous or dense ranges adjusted by feel. Pair with a live output element; for money and quantities offer direct numeric entry too.
Not for precise required values (a date of birth on a slider is a usability crime) and not with fewer than ~10 steps — that's a segmented control.
Native input[type=range]: arrow keys step, Home/End jump, aria-valuetext gives units ("$120"). The 26px thumb clears WCAG's 24px floor with a 44px touch halo.
HIG Sliders; Material 3 sliders; WCAG 2.2 · 2.5.7 dragging movements — which requires a single-pointer, non-dragging alternative, not merely a keyboard one; keyboard operability is 2.1.1 and both are shipped; 2.5.8 target size.
Core · Control
Toggle Switch
The switch means now — flip it and the thing is on. If anything else must happen first (a save button, a payment), it isn't a switch.
Binary settings with immediate effect: notifications, dark mode, autoplay. The label states the thing controlled, not the state ("Wi-Fi", never "On").
Not in forms that submit later — that's a checkbox. Never pre-flip a switch that spends the user's money or shares their data; defaults are a consent question, not a growth lever.
Built on a real checkbox input — Space toggles, state announces. Color is not the only state signal: the thumb position carries meaning in grayscale.
HIG Toggles; Material 3 switch; WCAG 2.2 · 1.4.1 use of color, 4.1.2 name-role-value; GDPR Art 7 — data toggles default off.
Core · Form
Checkbox & Radio
The oldest controls on the web, kept native and kept honest: checkboxes for any-of, radios for one-of, and the whole row is the target.
Checkbox for independent opt-ins and multi-select lists; radio when exactly one of 2–5 visible options must be chosen and the choice should be comparable at a glance.
Pre-ticked marketing checkboxes are a consent violation, not a conversion tactic. Radios with one option are a lie; radios with twelve are a select.
Native inputs with accent-color — full keyboard and screen-reader behaviour for free. Labels are clickable; groups get a fieldset/legend so the question travels with the answers.
WCAG 2.2 · 1.3.1 info & relationships (fieldset), 2.5.8 target size; GDPR Art 4(11) with Recital 32 — consent is an unambiguous affirmative act, so a pre-ticked box is not consent (Planet49, C-673/17) — and Art 7(4) for unbundling; ePrivacy consent conventions.
Core · Control
Segmented Control
All the options, all the time. The sliding thumb makes switching feel free — which is exactly when users explore.
2–5 short, mutually exclusive views or filters of the same content: List/Map, Weekly/Monthly, Delivery/Pickup. The selection changes the view immediately.
Not for actions (that's buttons) and not for navigation between unrelated destinations (that's tabs or a tab bar). Labels that truncate mean the control is the wrong choice.
Arrow keys move selection; the group carries a single tab stop. Selected state is encoded by the raised thumb and weight, not color alone.
HIG Segmented controls; Material 3 segmented buttons; WAI-ARIA radio-group pattern.
Core · Control
Quantity Stepper
Plus, minus, and a number that never surprises you. The humble stepper moves more units of physical goods than any carousel ever will.
Small integer adjustments with a sane range — cart quantities, tickets, guests. Bounds are enforced at the control: the minus disables at the minimum instead of erroring.
Not for large or unbounded numbers (use an input) and not for continuous values (use a slider). Removing the last item is a delete — hand off to a remove affordance, don't step to zero silently.
Buttons carry aria-labels ("Increase quantity"); the value is an output element announced on change. Both buttons hold the 44px target floor.
HIG Steppers; WCAG 2.2 · 4.1.3 status messages, 2.5.8 target size.
Core · Control
Chip & Tag
Small, tappable, and plural. Chips are how consumer products let people say "these, not those" without a form.
Filter sets, interest pickers, removable selections. Multi-select by default; a chip row scrolls horizontally on mobile rather than wrapping into a wall.
Chips are not buttons — they select, they don't submit. If only one may be active, show it as a segmented control or radio chips with explicit single-select semantics.
Toggle chips expose aria-pressed; removable chips make the ✕ its own labelled 24px+ target. Selection is encoded by fill inversion, not hue alone.
Material 3 chips (filter/input/assist); HIG Tokens & tags conventions; WCAG 2.2 · 2.5.8.
Core · Display
Badge & Count
Tiny, loud, and easy to abuse. A badge is a claim on attention — this system rations them like the currency they are.
Status that changes decisions (Shipped, Refunded, New) and unread counts that clear when acted on. A count badge must always be dismissible by doing the thing it points at.
Never manufacture urgency — a permanently red "3" that never clears trains users to ignore every badge you'll ever ship. Marketing does not get to borrow the notification badge.
Counts carry accessible text ("3 unread messages"), truncate at 99+, and pair color with position and text — status badges always contain a word, never only a color dot.
HIG notification badge conventions; Material 3 badges; WCAG 2.2 · 1.4.1 use of color.
Core · Display
Avatar & Presence
The pixel-sized proof there's a person here. Initials fall back gracefully, groups stack, and the green dot never lies.
Anywhere content has an author or a counterparty — posts, chats, reviews, orders ("packed by"). Deterministic gradient + initials when no photo exists, so the same user always looks the same.
Don't show presence unless it's real and consented — a fake "online" dot is a trust forfeiture. No avatars for system messages; robots get glyphs, not faces.
Images carry the person's name as alt text; presence pairs the dot with text nearby ("Active now"). Stacked groups expose a text count ("and 12 others").
WCAG 2.2 · 1.1.1 non-text content, 1.4.1 use of color; GDPR — presence is personal data, off by default where jurisdictions require.
Core · Display
Card
One idea per card, one card per idea. The hover lift is the system's handshake — content rises to meet you, gently.
Self-contained units in a browsable set — articles, places, playlists. The whole card is the link; inner actions stop propagation and get their own targets.
Not as a wrapper for everything — a settings screen of nested cards-in-cards is a spacing failure wearing borders. Sequential reading content wants a list, not a card grid.
One tab stop per card (the primary link), inner actions reachable after it. The lift transition is transform-only and disappears under reduced motion.
Material 3 cards; HIG content organisation; WCAG 2.2 · 2.4.4 link purpose in context.
Alpine mornings
Twelve cabins above the fog line, from $89 a night.
Focus mix
Two hours of instrumental momentum, refreshed weekly.
Core · Display
List & Cell
The inset grouped list is the load-bearing wall of every consumer app: settings, inboxes, results, orders. Icon, two lines, trailing detail — a grammar everyone already reads.
Homogeneous, vertically scanned items. The chevron means "more screen behind this"; a trailing control (switch, count) means the row is the whole story.
Don't mix row semantics in one group — navigation rows and toggle rows live in separate sections. Rich comparison shopping wants cards; lists are for scanning, not weighing.
Rows are ≥44px, entire row is the target, secondary text truncates rather than wraps at scan-breaking length. Semantics: a nav list is a list of links, not divs with click handlers.
HIG Lists and tables (inset grouped); Material 3 lists; WCAG 2.2 · 2.5.8, 1.3.1.
Core · Navigation-in-place
Tabs
Peer views of the same subject, underlined so the floor tells you where you stand. Tabs change the view; the tab bar (see Navigation) changes the world.
2–6 sibling facets of one thing — Posts / Replies / Media on a profile. State survives switching; nothing is lost by looking.
Not for sequential steps (that's a stepper flow) and not as an overflow bin — a "More" tab is information architecture giving up.
ARIA tabs pattern: arrow keys move, the tablist is one tab stop, selection follows the roving focus. The underline is position-encoded, not color-encoded.
WAI-ARIA tabs pattern; Material 3 tabs; HIG segmented alternatives guidance.
Core · Feedback
Toast & Snackbar
Confirmation that doesn't ask for anything back. Glass pill, four seconds, gone — and when it carries an Undo, it is quietly the most humane component in the system.
Outcomes that need acknowledgment but not action: saved, sent, added to bag. Pair destructive actions with an Undo toast instead of a pre-confirm dialog (see the Undo pattern).
Never for errors that require action — those need a banner or dialog that waits. Never stack three toasts deep; queue them. A toast with two buttons is a dialog in denial.
role="status" (polite announcement), pauses on hover/focus, and any action inside is reachable before timeout — WCAG gives users control over time limits, so Undo lingers.
Material 3 snackbar; WCAG 2.2 · 2.2.1 timing adjustable, 4.1.3 status messages.
Core · Overlay
Modal Dialog
The interface's interruption budget, spent one dialog at a time. If the user didn't cause it and can't lose anything, it doesn't get to be modal.
Decisions that block everything else: discard unsaved edits, confirm a payment change, sign in to continue. Title states the decision; buttons state outcomes, never "Yes/No".
Marketing does not get modals. Mobile prefers a bottom sheet for anything with options. And a modal on page load — before the user has done anything — is the fastest trust burn in the catalog.
Focus moves in, cycles inside, and returns to the trigger on close. Esc closes, scrim-click closes non-destructive dialogs, and the page behind is inert to screen readers.
WAI-ARIA dialog pattern; HIG Alerts (outcome-named buttons); WCAG 2.2 · 2.4.3 focus order, 2.1.2 no keyboard trap.
Core · Overlay
Bottom Sheet
The mobile-native answer to "show me options without leaving." It rises from where thumbs live, and the grabber is a promise: you can always push it back down.
Contextual actions, filters, and details on mobile — anything a desktop popover would do. Detents (half, full) let content and control share the screen.
Not for blocking decisions (that's a dialog — a sheet is dismissible by design) and not nested: a sheet opening a sheet means the flow wanted a full screen.
Swipe-down, scrim tap, and Esc all dismiss; the grabber is decorative while a real close button carries the accessible name. Focus management mirrors the dialog contract.
HIG Sheets (detents, grabber); Material 3 bottom sheets; WCAG 2.2 · 2.1.2, 2.5.7 (swipe has button alternative).
Options
Core · Overlay
Popover & Tooltip
Small truths anchored to the thing they describe. Tooltips name, popovers act — neither ever holds information that exists nowhere else.
Tooltip: naming icon controls on hover/focus, desktop only. Popover: a short menu of contextual actions anchored to a "…" trigger.
Tooltips don't exist on touch — anything a phone user needs cannot live in one. Errors never go in tooltips. A popover taller than half the screen is a sheet with the wrong name.
Tooltips appear on focus as well as hover, are dismissible with Esc, and stay hoverable (WCAG 1.4.13). Popover menus use the ARIA menu pattern with arrow-key navigation.
WCAG 2.2 · 1.4.13 content on hover or focus; WAI-ARIA menu & tooltip patterns; HIG Popovers.
Core · Feedback
Progress & Loading
Honesty about time. Determinate when the end is known, a spinner only when it's short, and a skeleton when there's a shape worth promising.
Bars for uploads and multi-step flows; rings for compact contexts; spinners for sub-2-second waits. Anything longer than ten seconds needs a cancel.
Never fake progress — a bar that crawls to 90% and parks is a lie the user physically feels. Don't spinner the whole page for one widget's fetch.
role="progressbar" with aria-valuenow; long operations announce completion via a live region. Spinners respect reduced motion by slowing, not vanishing.
HIG Progress indicators; Material 3 progress; WCAG 2.2 · 4.1.3 status messages.
Core · Feedback
Skeleton
A promise of shape. The screen commits to its layout before the data arrives, so loading feels like focus resolving rather than construction work.
Content with a predictable silhouette — feed items, cards, profiles — loading in 0.5–5 seconds. Skeleton geometry must match the real content, or the layout shift double-charges the wait.
Not for instant loads (flash of skeleton is worse than nothing) and not for unpredictable content where a spinner is more honest.
The container carries aria-busy="true" and a text status ("Loading feed"); the shimmer is decorative, aria-hidden, and static under reduced motion.
Material loading guidance; WCAG 2.2 · 2.3.3 animation from interactions; Core Web Vitals CLS discipline.
Alpine mornings
Twelve cabins above the fog line, from $89 a night.
Core · Navigation-in-place
Pagination & Dots
Numbered pages for destinations you'll cite and return to; dots for carousels you'll drift through. Both tell you where you are — that's the entire job.
Pagination where position matters — search results, order history. Page dots for short swipeable sets (≤6 slides), always paired with swipe.
Feeds don't paginate (see Infinite Scroll pattern for the trade). Dots beyond six are noise — show a count ("3 / 12") instead.
nav landmark with aria-label="Pagination"; the current page has aria-current="page". Dots are buttons with slide names, not empty spans.
HIG Page controls; WCAG 2.2 · 2.4.8 location, 4.1.2 name-role-value.
Core · Display
Accordion
Progressive disclosure on native semantics. Built on <details>, so it works with JavaScript disabled, and searchable-in-page in modern browsers.
FAQs, size guides, shipping details — secondary content most people skip and some people need. Multiple panels may be open; users manage their own attention.
Never hide critical-path content (price, total, cancellation terms) behind a fold. Auto-closing siblings punishes comparison — leave panels where users put them.
<summary> is natively focusable and toggles with Enter/Space; the chevron flips as a state signal in addition to the disclosure itself.
WAI-ARIA disclosure pattern (native <details>); WCAG 2.2 · 4.1.2; HIG disclosure controls.
What's your return policy?
Do you ship internationally?
How do I change my order?
Core · State
Empty State
The first screen most new users actually see. An empty state is onboarding wearing casual clothes — it names the value and hands over the first move.
First-run, cleared inbox, no results. Formula: what this space is for, why it's empty, one action that fills it. Zero-results always keeps the query editable and suggests a loosened filter.
Never a bare "No data". Never a dead end after a search — that's where shoppers leave. Don't guilt-trip ("It's lonely in here…") — charm, don't manipulate.
The heading is a real heading in the page outline; the illustration is decorative and aria-hidden; the action is a first-class button, not a text link whisper.
Material empty state guidance; NN/g empty-state conventions; WCAG 2.2 · 2.4.6 headings and labels.
Nothing saved yet
Tap the heart on anything you like and it lands here — synced across your devices.
Core · Feedback
Banner & Inline Alert
Persistent context that waits. Where a toast taps you on the shoulder and leaves, a banner sits down until the situation changes.
Conditions that remain true: payment method expiring, feature in beta, order delayed. Inline alerts attach to the thing they describe — a form error banner lives above the form it indicts.
Not for one-off confirmations (toast) and not stacked three deep — if everything is urgent, nothing is. Dismissible only if the condition is genuinely ignorable.
Errors use role="alert" (assertive), the rest role="status". Icon + word + color triple-encode severity; the dismiss button names what it dismisses.
Material 2 banners — dropped in Material 3 and never replaced, which is why this entry specifies one; WCAG 2.2 · 4.1.3 status messages, 1.4.1 use of colour.
Navigation
Tab Bar
Five doors at the bottom of the world. The tab bar is the most valuable real estate in a consumer app — every slot must earn daily use.
3–5 top-level, equally important destinations on mobile. Filled icon marks the active tab; each tab keeps its own navigation stack so switching never loses your place.
Never as an action bar — "Post" in slot three that opens a composer instead of a destination breaks the spatial model (if you do it, make it visually distinct and modal). Two tabs is a segmented control; six is a redesign.
Labels always visible — icon-only tab bars fail recognition tests everywhere they've been tried. Badges carry accessible counts. Safe-area padding is part of the component.
HIG Tab bars; Material 3 navigation bar (label conventions); WCAG 2.2 · 2.4.8.
Navigation
Drawer & Side Menu
The overflow home for secondary destinations — account, orders, help, legal. A drawer is where things go so the tab bar doesn't have to lie about their importance.
Secondary and account-level destinations, or the primary nav of dense multi-section products on tablet and desktop. Grouped, labelled, with the user's identity anchored at top.
Not as the only path to daily-use destinations on a phone — burying "Search" in a hamburger costs engagement measurably. Don't mirror the tab bar inside the drawer; duplicates confuse the map.
Opens as a modal region on mobile (focus trapped, Esc closes, scrim tap closes); on desktop it's a persistent nav landmark. The trigger announces expanded state.
Material 3 navigation drawer; WCAG 2.2 · 2.1.2 no keyboard trap, 4.1.2.
Navigation
Breadcrumb
The paper trail through a deep catalog. Mostly a desktop commerce citizen — on phones the back button carries this weight.
Hierarchies three levels or deeper — Home → Women → Shoes → Sneakers. Every crumb but the last is a real link; the last names the current page and links nowhere.
Not on flat products, not on mobile where it wraps into noise, and never as a step indicator in checkout — that's a progress stepper with different semantics.
nav[aria-label="Breadcrumb"] with an ordered list; the current page carries aria-current="page". Separators are decorative and hidden from screen readers.
WAI-ARIA breadcrumb pattern; schema.org BreadcrumbList (SEO); WCAG 2.2 · 2.4.8.
Navigation
Floating Action Button
One verb, promoted above the page. The FAB works when the screen has an obvious main thing to do — compose, add, capture — and fails everywhere else.
The single most common creative action of a screen: new message, add item, start workout. One per screen, thumb corner, persistent through scroll (or politely shrinking).
No FAB for destructive, rare, or ambiguous actions. Two FABs is zero FABs. If the action belongs to one list item rather than the screen, it belongs on the item.
56px target with a text label for screen readers ("Compose message"); never overlaps the last list item — scroll containers pad their bottom by the FAB's height.
Material 3 FAB; WCAG 2.2 · 2.5.8 target size, 2.4.7 focus visible.
Navigation
Large Title Header
The title starts as a headline and condenses into chrome as you scroll — orientation you feel rather than read. Scroll the demo.
Root screens of each tab — the moment of arrival. The large title gives the screen a name worth a headline; the condensed bar keeps it while content takes over.
Not on detail screens deep in a stack (content should lead) and not with titles longer than two words — "Order history & receipts" was never meant to be 34px.
The h1 exists once (the large form); the condensed bar mirrors it aria-hidden. The collapse is scroll-driven positioning, not animation — reduced motion changes nothing because nothing plays.
HIG Navigation bars (large titles); WCAG 2.2 · 1.3.1 heading structure.
Onboarding & Identity
Welcome Flow
Three screens, one promise each, and a skip that actually works. The best onboarding is mostly the product, sooner.
First launch only, ≤3 screens, each selling one outcome (not one feature). Progress dots show the end is near; the last screen lands on the primary action.
Never gate the product behind a tour a user can't skip. Don't ask for permissions here (see Permission Primer) and don't ask for registration before showing any value.
Skip is visible from screen one, tab-reachable first. Swipe advances but buttons exist for every gesture (WCAG 2.5.7). Seen-state persists — nobody sees the tour twice.
HIG Onboarding ("get to the app quickly"); Material onboarding guidance; WCAG 2.2 · 2.5.7 dragging movements.
Find your next favorite
Recommendations that learn what you love — not what advertisers wish you loved.
Onboarding & Identity
Sign-in & SSO
The fewest keystrokes between a person and their account. Platform sign-in first, email as the dignified fallback, passwords as the last resort they've become.
Offer the platform's native sign-in alongside any third-party login, then email. Order by user benefit, not by your data appetite.
Don't demand an account before demonstrating value — browse first, sign in to keep. Never dark-pattern the email option into 8px grey text to juice SSO adoption.
Buttons follow each provider's brand rules (their guidelines are contractual); autocomplete="email" and "current-password" keep managers working; errors never say which of email/password was wrong.
App Store Review Guideline 4.8 (offering an equivalent privacy-respecting login option); provider brand guidelines; WCAG 2.2 · 3.3.8 accessible authentication.
Onboarding & Identity
One-Time Code
Six boxes and thirty anxious seconds. Everything about this component exists to make the code arrive, paste, and verify itself.
Verifying possession of an email or phone. Auto-advance per digit, paste fills all six, auto-submit on the last — the user should never hunt for a Verify button.
Don't use OTP as the only factor for high-value changes (SIM-swap is real); pair with passkeys where it matters. Resend appears after a countdown, not never.
autocomplete="one-time-code" lets the OS offer the code from SMS; inputs are labelled "Digit 1 of 6"; WCAG 3.3.8: no transcription puzzle — paste always works.
WCAG 2.2 · 3.3.8 accessible authentication (minimum); HIG security code AutoFill conventions.
Onboarding & Identity
Passkey Prompt
The end of passwords, sold in one card. The design job is trust: say what a passkey is in one sentence, and make "not now" a real choice.
Right after a successful password or OTP sign-in — the moment the user has just felt the pain the passkey removes. One sentence of what, one of where it syncs.
Not during first-run before any sign-in exists, and never as a repeating nag — decline twice, stay quiet until the user visits security settings themselves.
"Not now" is same-size, adjacent, honest. The biometric icon row is decorative; the copy never claims biometrics leave the device — because they don't.
FIDO2 / WebAuthn UX conventions; HIG passkeys guidance; WCAG 2.2 · 3.3.8 (passkeys are the compliant path).
Sign in with your face or fingerprint
A passkey replaces your password with the way you already unlock this device. It syncs through your device account and never leaves your hardware unencrypted.
Onboarding & Identity
Profile Setup
Ask little, explain why, skip everything. Every optional field completed here is a gift the user gave you — design like you know it.
After account creation, one screen, only what the product needs on day one. Each request carries its reason inline ("your name appears on reviews").
No birthday "for your special offer", no gender without a product reason, no phone number as a growth hook. Data you can't justify inline is data you shouldn't collect.
Everything after the display name is skippable and says so. Photo upload has a keyboard path and never requires a camera. Progress persists — abandoning costs nothing.
GDPR Art 5(1)(c) data minimisation; App Store Guideline 5.1.1 (don't require unneeded personal data); WCAG 2.2 · 3.3.2.
Onboarding & Identity
Permission Primer
You get one shot at the OS permission dialog. The primer spends its own screen to make sure you take that shot at the moment the user already wants to say yes.
Immediately before a system permission request, triggered by a user action that needs it — asking for location when they tap "Find stores near me", not at launch.
Never chain three permission asks at first launch. Never re-prompt after a decline with the same pitch — respect the no, offer settings later when the feature is touched again.
The primer states exactly what is accessed, when, and what saying no costs. "Not now" keeps the app fully usable — degraded gracefully, never punitively.
HIG "request permission at the moment of need"; Play policy on prominent disclosure; GDPR Art 5(1)(b) purpose limitation, with Art 6 supplying the lawful basis that purpose is bound to.
See stores near you?
We use your location only while you're using the app to sort stores by distance. It's never stored or shared.
Onboarding & Identity
Consent Manager
The component regulators read first. Reject is as easy as accept, defaults are off, and the toggles do what they say — consent here is a designed artifact, not a legal speed bump.
First visit where consent-based processing applies, and permanently reachable from settings and footer. Purposes are separated, written in plain language, and individually controllable.
No "Accept all" in bold against "Manage options" in grey whisper — asymmetric prominence is the textbook dark pattern EU regulators cite. No consent walls for content that doesn't require it.
"Reject all" and "Accept all" are visual equals on the first layer. Non-essential toggles default off. Withdrawing is one screen away forever (GDPR: as easy to withdraw as to give).
GDPR Art 7 & Recital 32 (freely given, specific, unambiguous); ePrivacy; CCPA/CPRA opt-out rights; EU DSA Art 25 (no deceptive interface design).
Onboarding & Identity
Paywall & Plans
The most scrutinised screen in any subscription app — by users, by app review, by the FTC. This one converts by being legible: real prices, real terms, restore always visible.
At the moment of premium intent — tapping a locked feature — not as an ambush at launch. Plans show total billed price and period; the trial states when it converts and how to cancel.
No fake countdown timers, no pre-selected annual masquerading as monthly pricing, no hidden ✕. "Free trial" that means "we bill you in 72 hours unless you remember" gets rejected — by review and by users.
Close is visible from render. Price per period appears exactly as billed ("$59.99/year", not "$4.99/mo billed annually" alone). Restore purchases and terms are reachable without scrolling tricks.
App Store Review Guideline 3.1.2 (subscription clarity) & Schedule 2 rules; Play subscriptions policy; ROSCA 15 U.S.C. §8403 (clear disclosure before billing) — the surviving 16 CFR Part 425 reaches only prenotification plans, and the 2024 amendments that would have covered app subscriptions were vacated in July 2025.
Listen without limits
Offline downloads · lossless audio · no ads
Billed to your store account. Cancel in Settings → Subscriptions in two taps. Restore purchases · Terms
Commerce
Product Card
The unit of browsing. Image leads, price never hides, and the save affordance floats where thumbs already are.
Grid and carousel browsing. Image, name, one line of context, price, rating — nothing else survives the cut. The card links to detail; only save acts inline.
Never bury the price to "get them to detail" — hidden prices read as expensive. No fake "3 left!" scarcity unless inventory is genuinely tracked and true.
One link per card with a name that includes the product ("Ceramic pour-over set, $48"); the wishlist button is a separate labelled target announcing its toggled state.
WCAG 2.2 · 2.4.4 link purpose; FTC truth-in-advertising (scarcity claims must be true); schema.org Product markup.
Ceramic pour-over set
Hand-thrown · 4 colors
Trail runners
Recycled knit · true to size
Commerce
Price Display
Tabular, truthful, and complete. A price is a fact with typography — strikethroughs need a real former price, and the number you show is the number they pay.
Tabular numerals everywhere money appears so digits align in lists. Compare-at prices show savings as both amount and percentage; unit prices accompany multi-size goods.
No drip pricing — fees revealed at the last step are the single most-cited dark pattern in FTC enforcement. No fictitious strikethrough anchors that were never charged.
Strikethrough prices carry accessible context ("was $64, now $48") — <s> alone is silent on most screen readers. Currency symbols travel with the number, locale-formatted.
FTC Guides Against Deceptive Pricing (16 CFR 233); EU Price Indication Directive (prior-price rules); WCAG 2.2 · 1.3.1.
Commerce
Cart Line Item
Where second thoughts happen. Every line item makes changing your mind cheap — adjust, save for later, remove — because a trapped cart is an abandoned cart.
Cart and order review. Thumbnail, name, variant, unit price, quantity stepper, line total. Remove is one tap plus an undo toast — not a confirm dialog.
Don't inject upsells between line items — cross-sell lives below the list. Never auto-add items (warranty, insurance) the user must notice and remove; that's an FTC unfairness case with a design file.
Quantity changes announce the new line total politely. Remove names its item ("Remove trail runners"). Price changes since adding are flagged, not silently swapped.
FTC Section 5 unfairness (pre-checked add-ons); WCAG 2.2 · 4.1.3; Baymard cart usability conventions.
Commerce
Checkout Summary
No math surprises. Every fee has a name, the total is the largest number on screen, and it matches the charge to the cent.
The right rail (desktop) or pre-pay screen (mobile) of checkout. Subtotal, shipping, tax, discounts, total — each row aligned, tabular, updated live as options change.
Never a "service fee" that appears only here — junk fees at the summary stage are the FTC's current enforcement centerpiece. Never collapse the breakdown behind a tap on mobile.
Live updates announce via a polite region ("Total updated: $53.24"). The pay button repeats the total — the last thing read before commitment is the number.
FTC Rule on Unfair or Deceptive Fees, 16 CFR Part 464, in force since 12 May 2025 — its own scope is live-event tickets and short-term lodging, so all-in pricing is applied here as the honest generalisation of it rather than as a claim that it binds every checkout; EU Consumer Rights Directive Art 6 (total cost pre-order); WCAG 2.2 · 4.1.3.
Commerce
Payment Method
Radio rows for money. Wallets first (they convert best and typo least), saved cards next, new card last — and the selected row is unmistakable.
Checkout and settings. Each method shows its brand, its last four, and its expiry state. One is always selected; the default is the user's last successful method.
Never preselect a store credit line or BNPL the user didn't choose — payment defaults are a consent surface. Expired cards can't be selected, only fixed.
A real radio group: label reads "Visa ending 4242, expires 12/27". Adding a card uses autocomplete cc-attributes and never blocks paste.
PCI DSS v4.0 Req 3.4.1 — the standard permits BIN plus last four, so showing last four only is this system's own stricter rule rather than the requirement; card-network brand guidelines; WCAG 2.2 · 1.3.5 identify input purpose and 3.3.2 labels or instructions. (3.3.8 governs authentication steps; entering a card number is not one.)
Commerce
Promo Code
A tiny form with outsized feelings. Success celebrates with the exact amount saved; failure explains without blaming.
Checkout, collapsed behind "Have a code?" so full-price buyers aren't invited to leave and hunt coupons. Applies without page reload; the summary updates in the same breath.
Don't auto-apply a worse code over a better one. Expired codes say expired — "invalid code" for a code that worked yesterday teaches distrust.
Uppercases as-you-type (display only), trims whitespace on paste, result announced via status region. The applied state shows the code and its effect together, removable in one tap.
WCAG 2.2 · 3.3.1, 3.3.3 error suggestion, 4.1.3; FTC advertised-discount truthfulness.
Commerce
Ratings & Reviews
Social proof with a chain of custody. Stars summarise, distributions tell the truth, and "verified purchase" means the system checked.
Star input for collection (tap or drag, 1–5), star display plus count everywhere the product appears. Reviews sort by helpfulness with recency available.
Suppressing or reordering negative reviews violates the FTC's review rules — display practices are a legal surface now. No incentivised reviews without disclosure.
Display stars carry text ("4.6 out of 5, 1,942 ratings"); the input is keyboard-operable radios styled as stars. Half-star precision displays, never collects.
FTC Rule on Consumer Reviews and Testimonials (16 CFR 465); Consumer Review Fairness Act; WCAG 2.2 · 1.3.1.
Survived a week of rain in Portland and still looks new. Runs slightly large — I sized down and it's perfect.
Commerce
Save & Wishlist
The lowest-commitment yes in commerce. A save is a bookmark on desire — instant, reversible, synced, and never guilt-tripped.
A heart on every product surface, toggling instantly with optimistic UI and a toast pointing at the list. Saved items remember price at save time so drops can be shown truthfully.
Saving must not require sign-in to feel instant — save locally, merge on auth. Never spam "items in your wishlist are selling fast!" pushes without explicit opt-in to that exact category.
The heart is a toggle button with aria-pressed and a name including the product; the fill change pairs with the pressed state so color isn't the only signal.
WCAG 2.2 · 4.1.2 name-role-value; GDPR-conscious local-first storage; HIG feedback conventions.
Commerce
Order Tracking
The screen people open eleven times for one package. Its whole job is a truthful answer to "where is it and when" — everything else is decoration.
Post-purchase. Timeline of real states with timestamps, current state emphasized, delivery window as a range that narrows honestly as confidence grows.
No fake precision — "arriving 2:14 pm" from a model that knows ±3 hours erodes every future promise. A stuck state acknowledges being stuck and offers support before the user hunts for it.
The timeline is an ordered list; each step names its state and time. Status color is tripled with icons and text. Updates announce politely if the screen is open.
FTC Mail Order Rule (shipment timing representations); WCAG 2.2 · 1.3.1, 1.4.1.
Social
Feed Post
The atom of the social web: who, what, and three verbs. The layout is a contract with the reader — authorship always above content, actions always below it.
Any authored unit in a scrolling feed. Avatar + name + time anchor trust; the action row keeps to three or four verbs with live counts.
Sponsored posts wear the same anatomy plus an unmissable "Sponsored" label — camouflaged ads violate FTC endorsement rules and reader trust in the same move.
The post is an article with the author as its heading; action counts are part of each button's name ("Like, 1,204 likes"). Media carries author-provided alt text — the composer asks for it.
FTC Endorsement Guides (ad disclosure); WCAG 2.2 · 1.1.1, 4.1.2; EU DSA transparency for recommender systems.
Social
Comment Thread
Conversation with indentation as grammar. One level of nesting reads as reply; two reads as argument; three reads as nothing at all — so this system stops at one.
Discussion under any post or product. Bubble carries author + text; the meta row underneath holds time, like, reply. Deeper threads collapse behind "View 12 replies".
Don't autoplay into hostile territory — sort by "most liked" hides brigading better than "newest". Don't let the reply box push content; it stays docked.
Semantic list structure preserves thread relationships for screen readers ("reply to Ana"). Collapsed counts are buttons, not links-that-lie. Report is reachable on every comment.
WCAG 2.2 · 1.3.1; EU DSA Art 16 (notice mechanisms adjacent to content); community-safety conventions.
Right? Empty at 6am, chaos by 9.
Social
Reaction Bar
Six feelings on a glass shelf. The long-press reveal is one of the small delights consumer software is allowed — spent here because reacting is frequent, safe, and reversible.
Quick emotional response on posts and messages. Five or six options maximum — the palette is a vocabulary and vocabularies need to be memorisable.
Not for decisions or feedback with consequences (that's a survey or report). Don't A/B swap the emoji set weekly; meanings accrete through stability.
Long-press has a click/keyboard path (the bar opens from a labelled button too — WCAG 2.5.7). Each emoji button carries its name ("Love"). Selection announces and dismisses.
WCAG 2.2 · 2.1.1 keyboard — long-press is neither a dragging movement (2.5.7) nor a path-based gesture (2.5.1), so no criterion compels an alternative and this system ships one anyway; WAI-ARIA toolbar pattern; HIG feedback conventions.
Social
Chat Bubbles
Two voices, two sides, zero ambiguity. Yours right and tinted, theirs left and neutral — a convention so strong that breaking it reads as a bug.
1:1 and small-group messaging. Consecutive messages group under one timestamp; delivery state (sent, delivered, read) lives once at the thread's end, not on every bubble.
Read receipts are consent-gated and mutual — showing "read" to senders while hiding the setting is a dark pattern. Support bots must be visibly non-human.
The transcript is a log region; new messages announce without stealing focus. Bubble color carries ≥4.5:1 text; the typing indicator stills under reduced motion.
WCAG 2.2 · 4.1.3, 1.4.3; EU AI Act transparency (bot disclosure); messaging privacy norms (GDPR).
Social
Notification Item
A sentence with a face. Actor, verb, object, time — and unread state you can see from across the room. The list is an inbox, so it behaves like one.
The in-app notification center. Group by day, batch same-actor events ("Ana and 3 others liked…"), and deep-link to the exact object, never the home screen.
Marketing does not wear the notification costume — "Someone might have viewed your profile 👀" as engagement bait poisons the channel that ships real information.
Unread is background + dot + bolded text (triple-encoded); items mark read on visit and support mark-all. Each row is one link with a complete sentence as its name.
HIG Notifications ("valuable, not promotional"); Play FCM policy; WCAG 2.2 · 1.4.1.
Ana Reyes and 3 others liked your photo.
12 min agoTomas K. replied: "That stretch past the pier…"
1h agoMaya R. started following you.
YesterdaySocial
Follow Button
The smallest social contract. Following is loud, followed is quiet — the state change is the entire design, so it must be unmistakable and reversible in one tap.
Profiles, suggestions, discovery cards. Unfollowed is filled and inviting; following turns quiet secondary with the label changed — never just a color swap.
No confirm dialog on unfollow (it's reversible; asking makes it feel surveilled). Never follow anyone automatically — imported contacts get suggestions, not silent edges.
aria-pressed carries the state; the label text changes (Follow ↔ Following) so screen readers and grayscale users read the same truth. Optimistic update, quiet rollback on failure.
WCAG 2.2 · 4.1.2, 1.4.1; platform anti-spam norms (no auto-follow).
Social
Story Ring
A gradient halo that means "new, and it expires." The seen state — gray, quiet — is just as much the design as the rainbow.
Ephemeral content rails. Ring = unseen, gray = seen, no ring = no story. Your own slot leads with an explicit + affordance for creation.
Don't reset seen-state to farm taps — users notice, and the ring stops meaning anything. Don't put non-expiring content in the expiring costume.
Each story is a button: "Ana's story, unseen, 2 hours ago". Seen state is encoded by ring treatment plus order (unseen first), not color alone. The rail is keyboard-scrollable.
WCAG 2.2 · 1.4.1, 2.1.1; ephemeral-content honesty conventions.
Media
Video Player Controls
Controls that get out of the way and come back when called. Everything essential within one thumb arc: play, scrub, captions, volume.
Any owned playback surface. Controls fade after 3s of playback, return on tap/hover/focus. The scrubber shows buffered vs played; ±10s skips beat frame-precise dragging on touch.
Never autoplay with sound — muted autoplay with visible captions is the honest compromise. Don't hide captions behind a settings submenu; CC is a first-class control.
Full keyboard map (space, arrows, C for captions, F for fullscreen); controls are real buttons with names; fading controls never fade while focused (WCAG 2.1.1, 1.4.13).
WCAG 2.2 · 1.2.2 captions, 2.2.2 pause/stop/hide; HIG playback; Media Session API conventions.
Media
Mini Player
Playback that follows you around the app without blocking it. A glass bar above the tab bar: art, title, play, next — and a tap expands to the full stage.
Continuous audio/video while browsing elsewhere. Persistent across navigation, dismissible by swipe with a real stop — dismissing pauses, it doesn't secretly keep playing.
Not for content the user hasn't started. It never covers the tab bar or the last row of content — layouts reserve its height when active.
The bar is a region ("Now playing"); controls are named; the expand affordance is a real button as well as a tap surface. Swipe-dismiss has a button equivalent.
HIG now-playing conventions; WCAG 2.2 · 2.5.7, 4.1.2.
Media
Gallery & Lightbox
A grid that promises and a lightbox that delivers. The grid is uniform and dense; the lightbox is the one place chrome fully yields to the image.
Photo sets — products, listings, albums. Square grid crops for rhythm; the lightbox shows true aspect with pinch/double-tap zoom and swipe between images.
Don't lightbox single inline images that are already big enough. Don't trap scroll — reaching the end of a lightbox swipe returns to the grid, not to the first image forever.
Grid items are buttons naming their image; the lightbox is a dialog with arrow-key navigation, Esc close, and position announced ("Photo 3 of 8"). Zoom always has button + keyboard paths.
WCAG 2.2 · 2.5.7, 1.1.1; HIG image viewing conventions.
Media
Carousel
Scroll-snap, native momentum, and a peek of the next slide doing the affordance work. The browser already knows how to swipe — this component just stops fighting it.
Browsable peers where order is soft — featured collections, related items. The 82% slide width leaks the next card: visible continuation beats any arrow.
Never auto-rotate a carousel of content people read — rotation steals the thing they were reading. Critical content doesn't go in slide 3; nobody sees slide 3.
Native scroll means keyboard and screen-reader access come free; slides are list items with names. Any autoplay (hero promos only) pauses on hover, focus, and reduced motion.
WCAG 2.2 · 2.2.2 pause/stop/hide; CSS scroll-snap conventions; NN/g carousel research.
Media
Live Badge
Two words that must never lie: LIVE means now, and the pulse means the signal is real. The moment the stream ends, the badge dies with it.
Actually-live streams and events, on thumbnails and in players, paired with a viewer count when it's meaningful. Red, uppercase, pulsing dot — the convention is universal; keep it.
Never on premieres, reruns, or "live-style" drops — "LIVE" on recorded content is a trust forfeiture regulators call deceptive. Ended streams switch to "Streamed 2h ago" instantly.
The badge is text, not just color ("LIVE"), announced as part of the title. The pulse is decorative and stops under reduced motion without losing the label.
FTC deception standard (liveness claims); WCAG 2.2 · 1.4.1, 2.3.3.
Media
Captions
Most video is watched silent; captions are the soundtrack most people actually use. High contrast, two lines, and never covering the faces they transcribe.
All published video. Default on when the device is muted. Position bottom-center, lifting above controls when they're visible.
Auto-generated captions without a correction path aren't accessibility, they're liability diffusion — label them auto-generated and let creators fix them.
User-adjustable size and background opacity, honoring OS caption preferences where exposed. ≥4.5:1 against any video via scrim. Max two lines, ~42 chars each.
WCAG 2.2 · 1.2.2 captions (prerecorded), 1.2.4 (live); FCC caption quality rules; CVAA.
Growth · dark-pattern-free by construction
Onboarding Checklist
Progress you can feel. The checklist turns "set up your account" from a lecture into a game the user is already winning — because the first item arrives pre-checked.
Activation journeys with 3–5 real steps toward the product's core value. The endowed-progress head start (one item done at signup) is honest: they did create the account.
Steps that serve you, not them — "enable notifications" and "invite 3 friends" are not setup, they're acquisition wearing a checklist. Completion never gates paid-for functionality.
Progress announced on change ("2 of 4 complete"); dismissible for good once completed or explicitly hidden; each item deep-links to the actual task.
Endowed progress research (Nunes & Drèze); WCAG 2.2 · 4.1.3; EU DSA Art 25 (no manipulative pressure).
Growth · dark-pattern-free by construction
Streak & Achievement
Celebration without hostage-taking. A streak marks showing up; this one is designed so missing a day stings less than the habit is worth.
Genuine practice loops — learning, fitness, journaling — where consistency serves the user's own goal. Streak freezes and grace days are part of the component, not a paid add-on.
Not on consumption ("7-day shopping streak" serves nobody but the funnel). No guilt copy on breaks — "your streak is hurt 😢" notifications at 11pm are the pattern this entry exists to forbid.
The count carries text ("14-day streak, 5 of 7 days this week"); flame color pairs with the number. Celebration animation is one-shot and reduced-motion-gated.
EU DSA Art 25; FTC dark-pattern report (guilt-driven engagement); WCAG 2.2 · 2.3.3.
Life happens — you have 2 streak freezes, applied automatically.
Growth · dark-pattern-free by construction
Referral Card
Both sides of the deal on one card. Referrals work when the invitation is a gift, not an extraction — so the friend's reward leads.
After a moment of earned delight (first great order, milestone hit). State both rewards, the code, and the terms link — the whole deal, no asterisk archaeology.
Never auto-import and mass-message contacts; every invite is user-sent. No fake "3 friends joined!" social proof. Referral rewards that expire in 48 hours are pressure, not generosity.
Copy confirms via toast and status region; the code is selectable text, not an image; share uses the OS sheet with a clean pre-filled message the user can edit.
FTC endorsement rules (incentivised referrals disclose); CAN-SPAM / TCPA (user-initiated sends); WCAG 2.2 · 1.4.5.
Give $15, get $15
Friends get $15 off their first order. Once they order, you get $15 in credit. Full terms
Growth · dark-pattern-free by construction
Push Pre-Prompt
Permission with a menu. Instead of "allow notifications?", the primer asks which — orders only, or the social noise too — and the OS prompt fires only after a real yes.
At the first moment a notification would have helped ("your order shipped" beats any launch-time ask). Category toggles first, OS prompt second.
Never at first launch before value exists. Never re-prompt on a schedule. And the category promises are binding — routing marketing through the "order updates" channel is the lie that gets apps muted.
"Not now" is prominent and final until the user visits settings. Chosen categories map to real notification channels the OS exposes (Android) or the app respects (iOS).
HIG asking permission; Android notification channels; Play FCM policy; ePrivacy (marketing push is consent-based).
Growth · dark-pattern-free by construction
In-App Review Prompt
Ask happy people, once, at the right moment — and never intercept the unhappy into a private complaint box while herding fans to the store. That fork is now a violation, not a growth hack.
After a success the user caused (finished workout, delivered order), rate-limited far below the OS caps. Use the platform's native review API — it handles the UI and the throttling.
No sentiment-gating ("Enjoying the app?" → happy to store, unhappy to a form). The FTC's review rule bans review suppression; Apple and Google both prohibit review gating explicitly.
The prompt is dismissible, never repeats within the cooldown, and never blocks a task in progress. Feedback and rating are separate, both always reachable from settings.
FTC 16 CFR 465.7 (review suppression) — 465.4 is the separate offence of buying reviews; App Store Guideline 3.2.2(x) (no coercing or incentivising ratings) with the SKStoreReviewController prompt limit; Play in-app review API rules.
Enjoying it? Tell the store.
A rating takes two taps and genuinely helps. Having trouble instead? Talk to support — both paths are right here, no quiz first.
Growth · dark-pattern-free by construction
Survey & NPS
One question, honestly asked, instantly dismissible. Survey fatigue is a design failure — this component is rationed like the interruption it is.
A single 0–10 or emoji-scale question after a completed experience, inline or as a quiet card — never a modal over a task. Follow-up text is optional and says so.
Not during first-run (nothing to rate yet), not after failures (measure that from support volume, don't make the wounded fill forms), and never twice in one quarter for the same person.
The scale is a labelled radio group with keyboard flow; endpoints carry meaning text. Submitting acknowledges once, quietly. Declining is remembered.
WCAG 2.2 · 1.3.1, 4.1.3; research-ethics conventions (voluntary, no dark nudges).
Growth · dark-pattern-free by construction
What's New
Release notes people might actually read: three items, verbs first, each row deep-linking to the feature it announces. Shown once, then it's a page, not a prompt.
Meaningful user-facing changes after an update — new abilities, not refactors. One sheet per release maximum, dismissible instantly, revisitable from settings.
"Bug fixes and improvements" doesn't earn an interruption. Neither do upsells wearing a changelog costume — a "what's new" that's three premium pitches is an ad with a version number.
Standard sheet semantics (dismissible, focus-managed); each item is a real link; the seen-flag is per-version and survives reinstalls via account state.
HIG onboarding & release-note conventions; WCAG 2.2 · 2.4.4.
Trust & Safety
Report & Block
The exits from a bad interaction, always two taps away. Report feeds the system; block protects the person — the component never confuses whose problem each solves.
On every piece of user-generated content and every profile, via the overflow menu. Reporting asks one clarifying question, confirms receipt, and says what happens next.
Don't bury it four screens deep to keep report volume flattering. Block never requires a reason — protection is not a form. Neither action notifies the reported party of who acted.
Block takes effect immediately and optimistically — the content vanishes now, the network catches up. Both flows are fully keyboard-operable and confirm via status region.
EU DSA Art 16 (notice and action) & Art 20 (appeals); App Store Guideline 1.2 (UGC apps must have report/block); Play UGC policy.
Trust & Safety
Content Warning
A blur that respects both the viewer and the content. It names the category, offers the choice, and remembers the preference — informed consent at feed speed.
Sensitive-but-allowed media: graphic news, medical content, spoilers. The veil names the category specifically ("Graphic injury") so the choice is informed, not a dare.
Not as an engagement mechanic — mystery-blurring benign content to farm taps teaches users to ignore real warnings. Policy-violating content is removed, not veiled.
The reveal is an explicit button ("Show anyway"); the choice can persist per category in settings. The warning text is readable at full contrast on the blur.
EU DSA systemic-risk mitigation; App Store 1.2 / Play sensitive-content rules; WCAG 2.2 · 1.4.3.
This photo from a news story shows a surgical scene.
Trust & Safety
Age Gate
A door, not a decoration. Where children's privacy law applies, the gate is designed to be neutral — it doesn't wink, hint, or make the underage path retryable until it passes.
Before collecting personal data where COPPA/GDPR-K applies, and before age-restricted content or purchases. Ask once, neutrally ("When were you born?"), without stating the passing age.
No "you must be 18, enter your age 😉" framing that coaches the answer. Failing users aren't offered a back-button retry loop — the session remembers.
Neutral field order (year first coaches less), no data retained from failed gates beyond the session flag, and the under-age experience degrades kindly, never mocks.
COPPA · 16 CFR Part 312 (neutral age screening, FTC guidance); GDPR Art 8; UK Age Appropriate Design Code.
When were you born?
We use this to set up the right experience. It's not shown on your profile.
Trust & Safety
Privacy Dashboard
Every promise the consent screen made, auditable in one place. What's collected, why, and the switch to stop it — the settings page as a trust document.
One screen from settings root. Each row: the data category, its plain-language purpose, its current state, and its control. Changes take effect immediately and confirm.
No euphemisms — "personalisation data" that means location history gets called location history. Controls that only pretend (off = still collected, just hidden) are the deepest dark pattern there is.
Rows are grouped by data type with real switches; every state change announces. The page itself never requires consent to view.
GDPR Arts 13–15 (transparency & access); CCPA right to know; Apple privacy nutrition labels (App Store 5.1).
Trust & Safety
Data Rights
Download everything, delete everything — as self-service buttons, not support tickets. The delete flow states its consequences once, plainly, then does what it says.
Account settings, one level deep. Export produces a machine-readable archive with an ETA. Deletion explains scope, offers a cooling-off window, and confirms completion out-of-band.
No retention theatre — five "are you sure" screens, surprise discount offers, and a mandatory phone call are the FTC's canonical obstruction examples. One honest confirm is the ceiling.
The typed-confirm (for irreversibility) accepts paste and screen-reader input; deadlines and grace periods are stated in dates, not "soon".
GDPR Art 17 (erasure) & 20 (portability); CCPA deletion right; App Store 5.1.1(v) — account deletion in-app if creation is in-app.
Trust & Safety
Verified Badge
A checkmark is a claim the platform makes with its own reputation. This one means identity was checked — never that content is true, and never that a fee was paid unless the label says so.
Next to display names of identity-verified accounts, consistently everywhere the name appears. Tapping it explains exactly what was verified and when.
If verification is purchasable, the affordance must distinguish paid from vetted — one glyph for two meanings collapses both. Never auto-verify advertisers.
The badge has a text name ("Verified account") in the accessible label of the name it decorates — not a mystery blue blob. It's never separable from the name in truncation.
EU DSA Art 25 & trader traceability (Art 30); FTC deception standard; WCAG 2.2 · 1.1.1.
Trust & Safety
Security Checkup
An annual physical for the account, readable in ten seconds. Green means done, amber means one tap to fix — and the score never shames, it invites.
Reachable from settings; surfaced gently after security events (new device, password change). Each row pairs a state with its one-tap remedy.
Never cry wolf — "your account is at risk!" for an unused promo email address burns the channel needed for real alarms. Upsells (VPN, premium monitoring) don't wear the security costume.
States triple-encode (icon + word + color); every fix lands on the exact screen that fixes it; completed items confirm and re-verify on return.
NIST 800-63 authenticator guidance; WCAG 2.2 · 1.4.1; platform account-security conventions.
Patterns
Pull to Refresh
The gesture that taught a generation how feeds work. Pull, arm, release — with a visible threshold so the hand always knows whether letting go will act.
Time-ordered content the user plausibly wants fresher — feeds, inboxes, scores. The arrow flips at the arming threshold; a spinner holds until real content lands.
Not on content that doesn't change (settings) and never as the only refresh path — a visible refresh control exists for keyboards, switch access, and everyone the gesture excludes.
WCAG 2.5.7: single-pointer gesture with a button alternative. Completion announces ("Feed updated, 4 new posts"). Rubber-banding respects reduced motion.
HIG refresh content controls; WCAG 2.2 · 2.5.7 dragging movements, 4.1.3.
Patterns
Infinite Scroll vs Pages
Infinite scroll is a loan against the user's sense of time. This system spends it only where content is truly endless — and always installs a footer the scroll can land on.
Entertainment feeds with no meaningful end. Load-more happens ahead of the viewport; position restores perfectly on back-navigation — losing your place is the cardinal sin.
Goal-directed contexts — search results, order history, anything comparable — get pagination or "Load more" buttons: they preserve place, footer, and the feeling of progress. The footer must be reachable; content that flees the scrollbar fails WCAG and patience alike.
New batches announce count, focus is never stolen, and a "Back to top" affordance appears after two screens. Session-length nudges ("you're all caught up") are honest stopping points, not shame.
EU DSA Art 25 & recital 67 (attention-exploiting design); WCAG 2.2 · 2.4.1; NN/g infinite-scroll research.
Patterns
Undo, Not Confirm
Confirmation dialogs make everyone pay a tax because someone might err. Undo charges only the error, only when it happens — act immediately, offer the way back.
Reversible destructive actions: delete a message, archive a thread, remove from cart. The action executes optimistically; a toast holds the undo for ~6 seconds; the model really can restore.
Truly irreversible or high-stakes actions (delete account, send money, publish to everyone) keep a real confirm — undo is for the reversible, and pretending otherwise is worse than the dialog.
The undo control is focusable before timeout, the timer pauses on hover/focus, and the same action is also available in an activity/trash surface for the slow.
WCAG 2.2 · 2.2.1 timing adjustable, 3.3.4 error prevention; HIG undo conventions; NN/g forgiveness principle.
Patterns
Error Recovery
Errors are moments of maximum attention — the one time you're guaranteed a careful reader. Say what happened, what it cost, and what to do, in that order.
Every failure surface. The formula: plain-language what ("Couldn't send"), the stakes ("your message is saved as a draft"), the action ("Try again"). Input is never thrown away.
No error codes as headlines (keep them small, for support), no blame ("you entered an invalid…"), and no dead ends — every error screen has at least one button.
role="alert" for blocking failures; retry buttons debounce; after two failed retries the surface changes shape and offers support instead of hope.
WCAG 2.2 · 3.3.1, 3.3.3; NN/g error-message guidelines.
Couldn't upload your photo
The connection dropped mid-upload. Your edit is saved on this device — nothing was lost.
Error 1006 — mention this to support if it keeps happening.
Patterns
Offline Mode
The network is a feature the world sometimes turns off. Offline design keeps reading, queues writing, and tells the truth about both.
A quiet banner when connectivity drops; cached content stays readable and marked fresh-as-of; outgoing actions queue visibly ("will send when online") instead of failing.
Don't block the whole app behind a full-screen dinosaur when 90% of it is cached and useful. Don't retry forever silently — surface the queue so users can cancel stale intents.
The state change announces once (not per-scroll); queued items are inspectable; reconnection syncs and reports ("2 messages sent"). Timestamps mark cached content honestly.
HIG & Material offline guidance; WCAG 2.2 · 4.1.3; PWA offline-first conventions.
Patterns
Cancellation Flow
The truest test of a product's ethics: leaving must be as easy as arriving. One path, two screens, zero guilt — the FTC calls it click-to-cancel; this system calls it the default.
Subscriptions and memberships. Cancel lives where billing lives, works in-app end-to-end, states what's lost and when, and confirms in writing. One save-offer maximum, skippable in the same tap.
No retention mazes: chat-agent-only cancellation, guilt copy ("we'll miss you 😢" over a shrunken cancel link), surprise pause-instead defaults, or five-screen offer gauntlets. Each is an enforcement citation with a UI attached.
The path is discoverable by search ("cancel"), completable by keyboard, and ends in a dated confirmation ("Access until Aug 12, no further charges"). Resubscribing is equally easy — symmetry both ways.
ROSCA 15 U.S.C. §8403 and FTC Act §5 — note the 2024 “click-to-cancel” amendments to the Negative Option Rule were vacated in full by the Eighth Circuit on 8 July 2025, days before the compliance date, so ROSCA is what is actually in force; App Store 3.1.2 / Play subscription cancellation rules; EU Consumer Rights Directive 2011/83 Art 6.
Cancel your membership?
You'll keep full access until Aug 12. After that, no further charges. Your playlists and history stay saved for 12 months in case you return.
Patterns
Search & Filter
Query, refine, count — the loop behind every marketplace. Filters are chips you can see and remove one at a time; the result count updates with every change so cause never loses its effect.
Catalogs beyond one screen. Applied filters render as removable chips above results; a filter sheet batches complex refinement behind one "Show 142 results" commit button that always shows its count.
Never auto-apply filters the user didn't pick ("sponsored first" is a sort disclosure, not a default to hide). Zero results with active filters offers to loosen them, never a dead end.
Count changes announce politely; each chip's remove is a named target; "Clear all" appears at two or more filters. Filter state lives in the URL — shareable, restorable, honest.
WCAG 2.2 · 4.1.3, 2.5.8; EU DSA Art 27 (ranking transparency); Baymard filtering conventions.
Core
Date & Time Picker
The control people fight with most, because it is the one place a product insists on its own format instead of accepting yours. Take typing. Take pasting. Take “next Friday” if you can.
Any date the user must supply: a booking, a birthday, a delivery window. Pair a text field with a calendar — the field is the fast path for people who know the date, the calendar is the browsing path for people who are choosing one. For a range — a stay, an availability window — a two-month grid that carries state on the days themselves: price, sold out, closed.
Never for a date the user already knows by heart and can type in three seconds (a birthday behind a
twelve-tap calendar is hostile). Never a calendar-only control on mobile web where the native
<input type="date"> already carries the platform's own accessible picker.
Never a dropdown-triplet for a date of birth: typing “1994” beats paging back 360 months.
Grid is role="grid"; arrow keys move by day, PageUp/Down by month, Home/End to week ends.
The focused cell is the only tab stop. Disabled dates state why. Locale decides
day-of-week order and the DD/MM vs MM/DD reading — never the developer's timezone. Typed entry parses
forgivingly — 3/7, 03-07 and “Mar 7” all land on the same day.
WAI-ARIA Authoring Practices · Date Picker Dialog; WCAG 2.2 · 2.1.1 keyboard, 3.3.2 labels or instructions; HIG Pickers; Material 3 Date pickers.
Weekends are shown, not hidden — a disabled day still says why.
Core
Upload & Camera
Uploading is the moment a user hands you something they cannot easily replace. Show the file before you take it, show the progress while you take it, and let them take it back.
Photos, documents, avatars, receipts. Offer drag-and-drop and a real
<input type="file"> button — on mobile the button also opens the camera, and on
desktop it is the only path a keyboard user has.
More than one file means a list, not a counter: each row carries its own state and its own Remove.
Never a drop zone alone. Never a spinner with no bytes-so-far on a large file — an indeterminate spinner on a 90 MB video is a lie about whether anything is happening. Never silently strip EXIF without telling a user you did, and never silently keep GPS EXIF without telling them either. Never state a limit only by failing — size, count and type belong on the zone before the pick, not in the error after it.
Drop zone is a labelled button; progress is role="progressbar" with a live percentage;
failures name the reason (too large / wrong type / network) and keep the file selected so retry costs one
click, not a re-pick. Cancel is available for the whole upload. Drag is an enhancement and never the only
path (WCAG 2.5.7); Remove works mid-flight, not just after.
WCAG 2.2 · 4.1.3 status messages, 3.3.1 error identification; HIG Photos & camera access; App Store Review 5.1.1 (purpose strings); GDPR Art. 5(1)(c) data minimisation — location EXIF is personal data. WCAG 2.2 · 2.5.7 dragging movements.
Location data in this photo will be removed before upload. Why
Core
Multi-Step Form
Splitting a long form into steps does not make it shorter. It makes it survivable — but only if the user can see how far it goes, go back without loss, and leave without starting over.
Forms with more than roughly ten fields, or with branching (identity → address → payment). Group by the user's mental model, not by your database tables. Name the steps rather than numbering them: “Delivery” tells a user what is coming, “Step 2” does not.
Never to hide length — a five-step flow that never showed “5” is a dark pattern with a progress bar on it. Never validate a step only on submit of the last one. And never make Back destructive: if going back loses what was typed, it isn't Back, it's Restart. Never validate step N against something the user only learns at step N+2, and never lock Back to protect a funnel metric.
Each step is a <form> with its own heading; focus moves to that heading on advance and
the step is announced (“Step 2 of 4, Address”). Progress is a real
role="progressbar". State persists across reload — a network blip is not the user's
fault.
The rail is an ordered list with aria-current="step", so position is structure rather than
decoration.
WCAG 2.2 · 2.4.3 focus order, 3.3.4 error prevention, 3.3.7 redundant entry (don't ask twice for what you already have); Material 2 steppers — not carried into Material 3; NN/g progressive disclosure.
Step 1 of 4 · Your details
What you type is kept when you go back — and when you close the tab.
- Bag
- Delivery
- Payment
- Review
Address and speed — your details from last time are prefilled, not re-asked.
Core
Coach Mark
A tooltip you didn't ask for. It is the most abused component in consumer software, so it gets the strictest rule in this system: one, at the moment it is useful, dismissible forever.
Exactly one genuinely non-obvious affordance — a gesture, a hidden long-press, a new control in a place people already know. Trigger it on the screen where it is used, not on launch.
Never as a tour. A five-step carousel of coach marks on first launch is a confession that the interface failed, and nobody reads it — they tap Skip and now they've been taught that your hints are noise. Never to point at something you want to sell. Never twice. Never coach the obvious — a tip spent on “Tap search to search” teaches people to dismiss unread.
Focus moves into it and returns to the anchor on dismiss; Esc dismisses; it never traps. The dismissal is
persisted per-user, not per-session. It is a non-modal role="dialog", so a screen-reader user
is not silently stuck behind an overlay they can't perceive. It never covers the control it describes.
HIG Onboarding (“teach in context”); WCAG 2.2 · 1.4.13 content on hover or focus, 2.1.2 no keyboard trap; Material 3 Tooltips (rich).
Hold any saved item to reorder your list.
Dismiss it and it is gone for good — stored against the account, not the session.
Start one and friends add items to the same cart — one delivery fee, split at checkout.
Commerce
Subscription Management
The screen that decides whether a customer trusts you, because it is where they find out what you have been charging them and whether you made it hard to stop.
Any recurring charge. Show the plan, the exact next charge amount and date, the payment method, and the full charge history. Cancel sits on this screen — not three levels down, not in an email, not on a phone line.
Never let the renewal price differ from the price on this screen. Never bury cancel behind a chat widget or a “call us”. Never auto-upgrade a plan the user did not choose. Introductory pricing must state the price it becomes, and when — on the same screen, in the same size.
The next charge is a single unambiguous sentence, not a table the user must assemble. Cancellation is reachable in the same number of clicks it took to subscribe. A cancelled subscription still shows what remains paid-for and when access actually ends.
FTC negative-option / click-to-cancel rulemaking (cancel as easy as sign-up; confirm dates with counsel); EU Consumer Rights Directive 2011/83 (pre-contract information); App Store Review 3.1.2; Google Play Subscriptions policy.
Your card ending 4242 will be charged $89.00 on 12 March 2027. Nothing changes before then.
Two taps to subscribe. Two taps to leave. The cancellation flow →
Trust & Safety
Account Deletion
A door that only opens inwards is not a door. If a user can create an account in the app, they must be able to end it in the app — and know exactly what that ends.
Every app that supports account creation. The entry point lives in account settings, not support. State what is deleted, what is retained and why (tax records, fraud logs, legal hold), and when access actually stops.
Never offer “deactivate” as the only option and call it deletion. Never require an email to support, a phone call, or a web page the app refuses to link to. Never delete silently: an active subscription, an outstanding balance, or shared content owned by others must be surfaced before the button, not discovered after.
This is the one place a confirm is right — deletion is irreversible, so undo does not apply. Confirm by re-authenticating, not by typing DELETE in a box. Offer the data export first. Send a confirmation to the address on file, with a real grace window.
App Store Review 5.1.1(v) — in-app account deletion is required; Google Play Data deletion policy (in-app and web route); GDPR Art. 17 right to erasure and Art. 20 portability; CCPA/CPRA deletion rights.
- Your profile, posts and saved items are removed within 30 days.
- You have 14 days to change your mind. After that it cannot be undone.
- Purchase records are kept for 7 years — we are required to.
- Your Premium subscription is active. It will be cancelled; no further charges.
Confirmed by re-authenticating — not by typing the word “DELETE”. Typing a word proves nothing about who is holding the phone.
AI & Agents
AI Composer
The blank box is the hardest interface in consumer software: infinite capability, zero affordance. The composer's job is not to look clever — it is to tell you what this thing can do and where its edges are, before you waste a turn finding out.
Any open-ended AI surface. Show scope in the placeholder (“Ask about your orders” beats “Ask me anything”), show what it can see (attached context as removable chips), and give an explicit Stop while it is generating.
Never as a replacement for a control that already works — a chat box is a worse date picker than a date picker. Never claim “ask me anything” on a model that is scoped to your catalogue. Never send hidden context the user cannot see and cannot remove.
Enter sends, Shift+Enter is a newline, and the field grows to a cap then scrolls. Attached context is announced and each chip is individually removable by keyboard. Stop is focusable the instant generation starts — the ability to interrupt is part of the contract, not a nicety.
WCAG 2.2 · 3.3.2 labels or instructions, 2.1.1 keyboard; EU AI Act Art. 50 transparency (the user must know they are interacting with an AI system); HIG Machine Learning — set expectations, show the limits.
Answers are generated by AI and can be wrong. Order data is real.
AI & Agents
Status Orb
A spinner has one state. An agent doing real work has several, and the user's patience depends on knowing which one they're in — listening is a different wait than searching, and searching is a different wait than writing code. The orb's job is to spend that difference, not hide it.
Any agentic surface with more than one kind of latency — a chat that sometimes reads context, sometimes calls a tool, sometimes writes code. Name the state in both a visual and a plain-language string ("Agent searching…"), so the indicator never has to be decoded to be understood.
Don't invent a state the backend can't actually report — a "reasoning" animation over a system that only ever waits is theatre, and theatre erodes trust faster than a plain spinner would. Don't run more than four or five states in one product; past that, users stop learning the vocabulary.
role="img" with an aria-label derived from the state's status text, not the
state's internal id. Reduced motion freezes the current frame rather than hiding it — the state
stays legible without motion. Off-screen and backgrounded instances stop animating; nothing here should
cost a tab that isn't visible.
WCAG 2.2 · 2.3.3 animation from interactions, 1.4.2 audio/motion control by proxy; EU AI Act Art. 50 transparency (the state string doubles as an AI-disclosure surface, see AI Disclosure).
Agent listening…
Five of the full set's twenty hand-tuned states — the other fifteen (reasoning, planning, verifying, routing, syncing…) live in the standalone component. See all 20 in the live playground
AI & Agents
Streaming Response
Streaming solves latency and creates an accessibility problem in the same instant: text that changes sixty times a second is unusable to a screen reader. The fix is to stream to the eye and announce to the ear once.
Any generation long enough that a spinner would feel broken. Stream tokens into a region that is visually
live but aria-live="off", and announce the completed answer once, when it is done.
Never mark the streaming region aria-live="polite" — you will fire hundreds of
announcements and make the answer less accessible than a spinner. Never stream a
legal, medical or financial figure that could be misread mid-sentence. Never remove Stop.
“Generating” is announced via role="status"; the answer text is announced once on
completion. Stop halts immediately and keeps the partial output — discarding what the user
already read is a second failure on top of the first. Copy and Regenerate appear only when the answer is
whole.
WCAG 2.2 · 4.1.3 status messages, 2.2.2 pause, stop, hide (moving content); ARIA live-region practice; prefers-reduced-motion for the caret.
Stopping keeps what you already read.
AI & Agents
Sources & Citations
A citation is not decoration. It is the difference between an answer you can check and an answer you must simply believe — and a fabricated citation is worse than none, because it buys trust it hasn't earned.
Whenever the answer is grounded in retrievable material. Attach the source to the claim, not to the bottom of the message, and let the user open the passage that produced it — not just the domain it came from.
Never render a citation the system did not actually retrieve. Never cite a source the model didn't use because it “looks about right”. And never show a bare favicon row as a proxy for grounding — an unlinked logo is theatre.
Each citation is a real link with a discernible name (not “[1]” alone), states the date the source was retrieved, and opens the exact passage. Ungrounded sentences are visually distinguished and labelled — not by colour alone.
WCAG 2.2 · 2.4.4 link purpose, 1.4.1 use of colour; FTC guidance on substantiation and deceptive claims; EU AI Act Art. 50 transparency; NIST AI RMF (Measure — traceability of outputs).
Your return window for order #4821 closes on 29 August. Items must be unworn and in original packaging. Most customers get their refund within about a week.not grounded
“Delivered 15 Aug 2026. Returns accepted within 14 days of delivery.”
The last sentence has no source, so it says so. An unsupported sentence dressed as a supported one is the failure mode this component exists to prevent.
AI & Agents
Confidence & Abstention
The most valuable thing an AI product can say is “I don't know — here is someone who does.” Abstention is a feature. A confidently wrong answer costs more than no answer, and it costs the user, not you.
Whenever the cost of being wrong is real: money, health, legal, safety, or an irreversible action. Route low-confidence answers to a human, a verified document, or a deterministic tool — and say which.
Never render a raw model probability as a percentage badge — it reads as calibrated precision the model does not have, and users treat “87%” as a fact. Never use confidence to hedge every answer; a system that always says “I might be wrong” has said nothing.
Uncertainty is expressed in words and shape, never colour alone. The escalation path is a real control with a real destination and a stated response time. The state is announced — a screen-reader user must not miss the one sentence that says this answer is not reliable.
NIST AI RMF (Manage — risk-informed escalation); EU AI Act Art. 14 human oversight (high-risk uses); WCAG 2.2 · 1.4.1 use of colour; FTC Section 5 — unsubstantiated capability claims.
No percentage badges. A model's raw probability is not a calibrated confidence, and printing it as one is a lie with a decimal point.
AI & Agents
AI Disclosure & Content Credentials
If it was generated, say so — on the artefact, at the moment of viewing, in a form that survives a screenshot's worth of doubt. This is now law in some markets and it will be law in more.
Any synthetic or substantially AI-modified image, audio, video or text presented to a consumer; any chat interface where a person could reasonably think they are talking to a human. Attach provenance metadata (C2PA Content Credentials) as well as the visible mark.
Never bury the disclosure in a settings page or a footer. Never make it a hover-only tooltip. Never let it be strippable by a crop — the visible mark and the embedded credential are two mechanisms, and you need both because either alone can be defeated.
The disclosure is real text in the accessibility tree, not baked into a pixel. It is announced with the media, not after it. Tapping it explains what was generated and by what — a badge with no explanation is a shrug.
EU AI Act Art. 50 (transparency; machine-readable marking of synthetic content — confirm dates and scope with counsel); C2PA Content Credentials 2.x; FTC guidance on AI claims and endorsements; platform synthetic-media policies.
Two mechanisms, because either alone can be defeated: a visible mark a person can read, and an embedded credential a machine can verify after the crop.
AI & Agents
Agent Action Confirmation
An agent that can act on your behalf is a system that can be wrong on your behalf. The interface question is not “how do we make this smooth” — it is which actions a human must sign, and how we make that signature meaningful rather than reflexive.
Before any action that spends money, sends something to another person, changes a permission, or cannot be undone. Show the exact effect — the amount, the recipient, the scope — not a summary of the intent. The user is signing the payload, not the plan.
Never gate reversible reads and drafts — a confirm on everything is a confirm on nothing, and you will train the user to press Approve without looking. Never let a gate be satisfied by the agent itself. Never batch ten irreversible actions behind one Approve.
Approve is never the default focus. The consequence is stated before the buttons and is announced. Editing the payload is possible from the gate — if the only options are Approve and Cancel, the user with a nearly-right action has to start over, and will approve the wrong thing instead.
EU AI Act Art. 14 human oversight; NIST AI RMF (Govern — accountability for automated actions); PSD2 SCA for payment initiation; WCAG 2.2 · 3.3.4 error prevention (legal, financial, data).
Approve is not the default focus, and the button carries the amount — a button that just says “Approve” can be pressed without reading.
AI & Agents
Agent Activity Trace
When something acts for you while you are not looking, the receipt is the product. A trace is how a user audits a decision they didn't watch — and how they find the moment it went wrong.
Any agent that runs multi-step or in the background. Log what it read, what it did, what it was refused, and what it cost — with timestamps and a link back to each artefact it touched.
Never as raw chain-of-thought — it is not a log, it is unverified narration, and showing it invites the user to trust reasoning nobody checked. Log tool calls and effects, which are facts. Never omit the failed and blocked steps: a trace that only records successes is marketing.
The trace is a semantic list, newest-first, readable without expanding. Blocked steps state the rule that blocked them. Every entry is addressable, so a support conversation can point at a line rather than describe it.
EU AI Act Art. 12 record-keeping / logging; NIST AI RMF (Measure — traceability); GDPR Art. 22 (a route to contest an automated decision needs a record of it); SR 11-7 effective challenge, in the regulated sibling of this system.
spend > $0 requires a human.The blocked line is the most important line on this screen. A trace that only shows successes is not a record, it is a brochure.
AI & Agents
Prompt Starters
Starters are not decoration on an empty state — they are the only honest documentation an AI surface has. Each one is a promise: this is a thing I can actually do.
On the empty state, and as follow-ups after an answer. Derive them from real capability and real user context — “Where is order #4821?” beats “Tell me a joke” on a retail app, because one is what the surface is for.
Never suggest something the system cannot do — the user tries it, it fails, and now every suggestion is suspect. Never make them the only path (the box must still take free text). Never use them to upsell: a “starter” that opens a paywall is an ad wearing a helpful hat.
Real buttons in a list, reachable by keyboard, each with a full accessible name (not truncated). Selecting one puts the text in the composer — editable, not sent — so the user keeps authorship.
HIG Machine Learning — “set expectations, offer examples”; WCAG 2.2 · 2.4.6 headings and labels, 2.5.8 target size; NN/g empty-state guidance.
AI & Agents
Feedback & Correction
A thumbs-down that goes into a dashboard nobody reads is a complaint box in an empty building. Feedback earns its place only if the user can see what it changed — at minimum, for them.
On every generated answer. Offer a fast signal (helpful / not) and a real correction path — the user usually knows the right answer and is willing to type it if you make it worth two seconds.
Never let the thumbs be the only route for harm — harmful, unsafe, or defamatory output needs a Report path with a human at the end, not an aggregate metric. Never say “Thanks, this helps us improve” if it does not. Never treat the correction as training data without saying so.
Buttons are toggles with aria-pressed and unique names (“Mark this answer
unhelpful”, not “thumbs down”). Submitting is confirmed via role="status".
The correction is applied to the conversation immediately, so it is worth the effort now, not
hypothetically in the next model.
GDPR Art. 16 right to rectification (if the output is personal data, correction is a right, not a courtesy); DSA Art. 16 notice-and-action for illegal content; NIST AI RMF (Manage — incident feedback loops); WCAG 2.2 · 4.1.2 name, role, value.
Corrections apply to this conversation immediately. Harm reports go to a human, not a metric.
AI & Agents
Memory & Context
An assistant that remembers is useful. An assistant that remembers invisibly is surveillance with a friendly voice. The rule is simple: if it remembered it, you can read it, and you can delete it.
Whenever the system carries anything across sessions. Every remembered item is a discrete, human-readable row — what it learned, when, and from which conversation — with a delete on the row itself.
Never store an inference the user never stated as if it were a fact they told you (“has children” inferred from a search is a guess, and it will be wrong about someone in a way that hurts). Never remember special-category data by default. Never make deletion “forget in future answers” while the row stays on your servers.
Memory is a list, not a paragraph. Deletion is immediate and confirmed via role="status".
A global off switch exists and is honoured. New memories are announced when written, not discovered later
in an answer.
GDPR Art. 5 (purpose limitation, minimisation), Art. 9 (special categories), Art. 17 erasure; CCPA/CPRA right to delete; App Store Privacy Nutrition Labels; COPPA (no behavioural profiling of children).
Inferred memories say inferred. A guess presented as something you told us is the quiet way a product starts lying to you about yourself.
AI & Agents
Training & Personalisation Controls
Two different questions get collapsed into one toggle by most products, and it is not an accident: “use my data to personalise my experience” and “use my data to train your model” are not the same deal.
Wherever user content can feed personalisation, training, or human review. Split the switches, because they are separate decisions with separate beneficiaries — and state the consequence of each in the row itself.
Never bundle training consent into the terms of service and call it a choice. Never default training on for minors. Never pre-tick. Never make opting out of training silently degrade an unrelated feature — that is a penalty dressed as a consequence, and consent obtained under it is not freely given.
Switches are symmetrical: on and off are the same number of taps, the same visual weight, no “are you sure you want to lose out?” interstitial. Each row states what changes. Changes take effect immediately and are confirmed.
GDPR Art. 7 (freely given, unbundled, as easy to withdraw), Art. 21 objection, Art. 22 automated decisions; EU AI Act transparency duties; App Tracking Transparency; COPPA (verifiable parental consent).
No “are you sure you want to lose out?” screen on the way out. If leaving costs more taps than joining, it was never consent.
AI & Agents
AI Summary in Search
Summarising other people's work at the top of a results page is a redistribution of attention. Do it in a way that still sends the reader — and the credit — onward.
When a query has a synthesisable answer across sources the user would otherwise open one by one. The summary sits above the results, not instead of them, and each claim links to the source that produced it.
Never for a query where being wrong is expensive (dosage, legal deadlines, financial figures) — show the source, not a paraphrase of it. Never summarise a source you are also burying. Never present a summary with no route to what it summarised: that is not search, it is a wall.
The summary is labelled AI-generated before it is read, is skippable by a screen-reader user in one keystroke (it is a landmark, not an unnamed div), and never occupies the entire first viewport on mobile — the results must be visible without scrolling past an answer the user did not ask for.
EU AI Act Art. 50 transparency; FTC guidance on deceptive presentation; WCAG 2.2 · 2.4.1 bypass blocks, 1.3.1 info and relationships; copyright and DSM Art. 15 press-publisher rights — substance, not just attribution.
AI & Agents
Refusal & Human Escalation
Every AI product eventually meets the request it should not answer. The design question is what happens in that second — because a refusal with no exit is just a door closing on someone who came to you for help.
Regulated advice, safety-critical questions, disputes, distress, and anything the system has been instructed not to do. Say that it won't, say why in one plain sentence, and hand over to a path that actually resolves it.
Never refuse into a void — a refusal with no route is worse than an unhelpful answer, because the user now has neither. Never moralise. Never refuse a legitimate question because it merely resembles a forbidden one, and never make the user re-explain everything to the human you finally hand them to.
The escalation control is a real button with a real destination and a stated response time. Context transfers with the user — the human sees the conversation. If the topic is distress, the route to a person is offered immediately and is not buried under a policy paragraph.
EU AI Act Art. 14 human oversight; DSA Art. 20 internal complaint-handling; App Store Review 1.1/5.1 (safety and sensitive content); NIST AI RMF (Manage — escalation and incident response).
I can't tell you whether to dispute this charge — that's a decision with money and a deadline attached, and it needs a person who can act on your account.
They'll see this conversation — you won't start over.
One plain sentence of why. One real door. No lecture.
AI & Agents
Voice Agent
Voice removes the screen, and with it every affordance you were relying on. What is left has to carry the whole contract: that it is listening, that it is a machine, and that you can cut it off.
Hands-busy, eyes-busy, or accessibility-first contexts. The mic state must be unambiguous and continuously visible — listening, thinking, speaking — and barge-in must work: the user can interrupt mid-sentence and the agent stops instantly.
Never hot-mic without an unmistakable indicator. Never keep a recording the user wasn't told about — in two-party-consent jurisdictions that is not a UX choice, it is a legal one. Never make voice the only channel: a person who cannot speak, or cannot be overheard, must have the same product.
A live transcript runs alongside the audio — deaf and hard-of-hearing users get the same product, and everyone else gets a record. State changes are announced. A visible Stop is always present, and the agent identifies itself as an AI at the start of the call, out loud.
EU AI Act Art. 50 (a person must be told they are talking to an AI); two-party-consent recording laws (e.g. CA Penal Code §632 — confirm per jurisdiction with counsel); WCAG 2.2 · 1.2.4 captions (live), 2.5.4 motion actuation; HIG Siri & voice.
Not listening
Agent — This is an AI assistant. This call is not recorded.
The transcript is not an accessibility afterthought — it is the record. Speak over it and it stops mid-word, because a machine that has to finish its sentence is a machine that isn't listening.
AI & Agents
Tool & Data Grants
The permission surface of the MCP era. An agent's power comes from its tools — so every tool and every data source is its own grant: scoped, separately revocable, and visible in one place. "Allow everything" is not a setting, it's a surrender.
Wherever an agent can touch user data or external tools. One row per grant, each stating its scope in operational terms — "read your calendar", "draft but never send" — with the narrowest scope as the offered default.
Never a single master toggle that bundles read, write, and spend. Never expand a grant silently in an update — new capability means a new ask. Payments and sends are never part of any bundle; they are always their own explicit grant.
Each grant is a labelled switch announcing scope and state; revoking takes effect immediately and is confirmed. Every grant change is written to the activity trace — permissions and audit are one system, not two.
GDPR Art 5(1)(b) purpose limitation and Art 5(1)(c) data minimisation — a grant is a purpose, and its scope is the minimisation; EU AI Act Art 14 human oversight; least-privilege conventions from OAuth scope design.
AI & Agents
Background Agent Tasks
Agents work in minutes, not milliseconds — so the queue is a first-class surface. Four honest states: queued, working, needs you, done. "Needs you" is the interesting one — it means the agent hit a gate and stopped, which is the system working, not failing.
Any agent task longer than a few seconds: research, multi-step bookings, batch edits. The user leaves, the task continues, completion notifies through the channel the user already approved.
Never run irreversible steps while unattended — those park the task in "needs you" until the gate is signed. Never show a spinner with no cancel: a task you can't stop isn't yours, you're its.
State changes announce politely; cancel is instant and keeps partial results; "needs you" deep-links to the exact gate. Estimated time is a range, honestly widened when unknown.
EU AI Act Art 14 (interruptibility as effective oversight); WCAG 2.2 · 4.1.3 status messages; HIG background task conventions.
AI & Agents
Mode & Model Picker
Fast or thorough is a real decision users can make — if the trade-off is stated in outcomes, not model names. Nobody should need to know what a parameter count is to choose how carefully their question gets answered.
When modes differ in ways the user can feel: speed, depth, cost. Describe each in outcome language ("answers in seconds, may miss nuance") and show the price difference exactly where the choice is made.
Don't market version numbers to people who can't evaluate them — "v5-turbo-max" is noise wearing a spec. Don't default to the most expensive mode, and never switch modes silently mid-conversation to save cost (see Usage Meter: degradation is disclosed).
A radio group with outcome-labelled options; the active mode is visible in the composer at all times, not buried in settings. Changing modes announces and applies to the next turn, stated explicitly.
EU AI Act Art 50 transparency; FTC clarity on charges (paid modes state their price at the decision point); WCAG 2.2 · 4.1.2.
AI & Agents
Ghost Text & Suggested Edits
The most intimate AI surface: inside the user's own sentence. The contract is absolute — suggested text is unmistakably not-yet-yours, accepting it is always an explicit act, and your words are never overwritten.
Completions in composers, reply suggestions, edit proposals. Ghost text renders in the suggestion style; Tab or a button accepts, Esc or typing through dismisses — both directions keyboard-first.
Never auto-commit a suggestion on blur, send, or timeout — an unaccepted suggestion that ships is the system putting words in the user's mouth. No suggestions in password, legal-name, or payment fields, ever.
The suggestion is distinguished by more than color — style plus an announced prefix ("Suggestion:") so screen-reader users hear the boundary sighted users see (WCAG 1.4.1). Accept and dismiss both have visible button equivalents on touch.
WCAG 2.2 · 1.4.1 use of color, 2.1.1 keyboard; HIG Machine Learning — corrections (user stays the author).
Thanks for the invite — I'd love to come. What can I bring?
Ghost style + announced "Suggestion:" prefix — the boundary is audible, not just visible.
AI & Agents
Human ↔ Agent Handoff
When an agent can drive a session — filling a form, working a screen — exactly one question must never be ambiguous: who is driving right now. The handoff banner answers it at all times, and the wheel is always within reach.
Any surface where an agent acts on the user's behalf in real time. A persistent banner states who's driving; take-over is one tap and instant; the agent announces intent ("filling shipping address") as it works.
Never let the agent keep driving on a screen the user has started touching — human input always wins the wheel. No invisible sessions: an agent acting with no banner is indistinguishable from a compromise.
Pause/take-over is keyboard-reachable at all times and works mid-action. On resume, the user gets a delta recap — what changed while the agent drove — before anything else happens.
EU AI Act Art 14 (oversight must be effective, not nominal — interruptibility is the test); WCAG 2.2 · 2.1.1; EU AI Act Art 50 (the agent's presence is disclosed).
Intent is announced as it works; your first touch on the screen also takes the wheel.
AI & Agents
Usage & Cost Meter
AI features have a meter running, and hiding it is a pricing dark pattern with extra steps. The meter shows what's spent, what's left, and — critically — what happens at the cap, before the cap.
Anywhere AI usage is limited or billed: credits, daily message caps, minutes. Visible from the surface that spends it, not three screens away — the cost of an action is part of the action.
Never let a user discover the cap by hitting it mid-task. Never silently degrade to a cheaper model at the limit — if quality drops at the cap, the meter says so where the choice is made (see Mode Picker).
The meter is a labelled progressbar with numbers, not just a bar; crossing 80% announces once. Reset timing is a date ("resets Aug 1"), never "soon". Paid top-ups state price before the tap.
FTC all-in pricing discipline (the cost is disclosed where it's incurred); App Store 3.1 (in-app purchase clarity); WCAG 2.2 · 4.1.3, 1.4.1.
Resets Aug 1 · past the cap, Fast mode stays free — stated here, not discovered there.
AI & Agents
Generated Artifact Card
When AI output is a thing — an image, a document, an itinerary — it stops being a message and becomes an object with duties: versions that don't destroy each other, provenance you can open, and a disclosure that survives export.
Any generation the user will keep, edit, or share. The card carries version history (regenerate is a new version, not an overwrite), an openable provenance panel, and export that embeds the credential.
Never overwrite v1 because the user asked for a tweak — regret is a workflow, not an edge case. Never strip the provenance on export to make the output look hand-made; that's the disclosure rule inverted.
Versions are a labelled radio row; switching announces. Provenance (model, prompt, edits) is a disclosure panel, not a tooltip. The AI-made mark meets contrast on any artwork via scrim.
EU AI Act Art 50 (synthetic content marking); C2PA 2.x content credentials; GDPR Art 17 (deleting an artifact deletes its versions).
Birthday invite art
AI-madeRegenerating never overwrites — v1 and v2 are one tap back. Export embeds the content credential.
AI & Agents
Capability Disclosure
The first screen of any AI feature decides every later disappointment. Three things it can do, three it can't, one line about data — the anti-magic show. Underclaiming here is the cheapest trust you will ever buy.
First run of any AI surface, and permanently reachable from its header. Capabilities in user outcomes, limits in plain sentences, and the data line links straight to the grants screen.
No "magic" framing, no ∞ sparkles promising everything — capability overclaim is an FTC deception issue now, not just a UX smell. Don't bury the limits below the fold of an unscrollable card.
Can and can't lists are real lists with icon + text (never icon-only); the card is dismissible and revisitable; the data line is one sentence with a working link, not a policy PDF.
EU AI Act Art 50 transparency; FTC deception standard (capability claims); HIG Machine Learning — set accurate expectations.
Social
Profile Header
A person's front door: identity above the fold, numbers that mean something, one primary action. Everything else on the profile is furniture — this is the handshake.
The top of any profile: avatar, display name + handle, verified state, a two-line bio, three stats maximum, and the follow/message pair. Stats are tappable — a count you can't inspect is a boast.
Don't stack six stats — followers, following, and one domain number (posts, reviews, runs) is the ceiling. Never hide the handle in favor of display name only; the handle is the verifiable identity.
The header reads as one landmark: name is the page's h1, stats are labelled links ("1,204 followers"), and the follow button announces its state change. Bio links are real links.
WCAG 2.2 · 1.3.1 headings, 2.4.4 link purpose; EU DSA Art 30 (trader identity where accounts sell); verified-badge conventions (see Trust & Safety).
Ana Reyes
@anarunsSunrise runner · city photographer. Everything before 7am.
Social
Message Inbox
The conversation list is triage, not archaeology: who, the last line, how long ago, and whether it needs you — readable in a glance per row. Strangers wait in Requests, not in your face.
Any messaging surface. Rows: avatar + presence, name, one truncated preview line, timestamp, unread count. A Requests folder holds non-connections — consent applies to attention too.
No promotional "conversations" from the platform injected into the inbox — a brand that fakes being your friend burns the surface for everyone. Muted threads never bubble to the top on new messages.
Unread is triple-encoded (dot + bold + count in the accessible name). Swipe actions (mute, archive) all exist in the long-press/overflow menu too — gestures are shortcuts, never the only door.
WCAG 2.2 · 2.5.7 dragging movements, 1.4.1; ePrivacy (unsolicited messaging consent); platform anti-spam norms.
Social
Poll & Voting
The lightest form of speech. One tap to vote, results the moment you have — and never the moment before, because seeing the crowd first changes the answer.
Quick opinion capture in feeds and stories, 2–4 options, with a visible close time. Results render as labelled bars with percentages and the total count — your choice stays marked.
Results are hidden until you vote (or the poll closes) — pre-voting visibility is a conformity machine. Never for consequential decisions wearing casual clothes; a poll is not consent, feedback, or a survey.
Options are a radio group before voting and a results list after; the flip announces ("You voted Trail. Trail 64%, Road 36%, 2,140 votes"). Bars pair width with printed percentages — never width alone.
WCAG 2.2 · 1.4.1, 4.1.3; research-method honesty (no result-peeking bias); EU DSA Art 25.
Social
Mentions & Hashtags
The wiring of the social graph: @ points at a person, # points at a room. Both are entities the moment they're typed — colored, linked, and accountable.
Composer autocomplete triggers on @ and # with a ranked shortlist (people you know first). Rendered mentions and tags are real links with distinct styling that survives grayscale.
Mentioning is not consent to be dragged into anything — mass-mention spam is rate-limited and mentions from strangers are a notification setting, not a right. Never linkify inside code or quoted text.
The autocomplete is an ARIA combobox (arrow keys, Enter, Esc); inserted entities are single tokens — one backspace removes the whole mention. Mentioned users can untag themselves.
WAI-ARIA combobox pattern; WCAG 2.2 · 1.4.1; EU DSA (notice mechanisms extend to tags of people).
Social
Live Stream Chat
Thousands of voices in a phone-width column. The design job is legibility under flood: pinned context stays put, moderation is one tap, and the flow never steals your scroll position.
Chat beside live video. New messages flow at the bottom; scrolling up pauses auto-follow and shows a "back to live" pill with the missed count. The creator's pinned message holds the top.
Never auto-scroll a user who scrolled up — stolen scroll is the fastest way to make chat unreadable. Slow mode and follower-only mode are creator tools, disclosed in the composer, not silent filters.
The stream is a log region with announcements throttled (a screen reader must never receive 40 messages a second); report lives on every message via long-press and overflow alike.
WCAG 2.2 · 4.1.3 (throttled announcements), 2.2.2; EU DSA Art 16 (report adjacency); App Store 1.2 (UGC moderation).
MOD · Tomas Keep it kind, keep it moving
runwithmaya that ridge view 😍😍
coastal.kev pace group for 6:00/km?
anika_t joining from Osaka 👋
Social
Link Preview Card
The unfurled URL: image, title, domain. Its one non-negotiable job is telling the truth about where a tap will take you — the domain is the security surface, not a caption.
Links in chats, posts, and DMs. Show the real destination domain prominently; strip tracking params from the display; let the sender remove the preview (keeping the plain link).
Never let the page's self-declared title bury the domain — "Your package is waiting" over a typosquatted domain is the phishing pattern previews must expose, not launder.
The card is one link whose accessible name is "title, on domain"; preview images are decorative. Known-bad domains get an interstitial, and shorteners resolve to their final destination in the label.
Open Graph conventions; FTC deception standard (misleading destinations); WCAG 2.2 · 2.4.4.
Core · Display
Stats & Sparkline Card
Consumer analytics — screen time, spending, steps — is one number, one direction, one tiny chart. The card answers "how am I doing" before the eye finishes landing on it.
Personal dashboards and summaries. Anatomy: the number (tabular, big), the delta with an explicit direction word, and a sparkline for shape — labelled with its time range, always.
No unlabelled axes pretending to be neutral — a sparkline that starts at yesterday's low is an argument, not a chart. Deltas on spending say whether up is bad; green ≠ universally good.
The sparkline is decorative with the story in text ("Spending down 12% vs last month, $342 of your $400 budget"); direction pairs arrow + word, never color alone (WCAG 1.4.1).
WCAG 2.2 · 1.4.1, 1.1.1; chart-honesty conventions (labelled ranges, honest baselines).
Core · Form
Address Form
The most abandoned form in commerce, and the most international. One search field does most of the work; the rest adapts to the country instead of arguing with it.
Checkout and profile. Lead with autocomplete search; expand to editable fields on selection. Field set, order, and labels follow the chosen country — ZIP is not a universal concept.
Never validate international addresses against US assumptions (required state, 5-digit postal). Never block manual entry — autocomplete is a shortcut, not a gate; new buildings exist.
Full autocomplete attributes (address-line1, postal-code, country) keep browser autofill working — the fastest address form is the one the browser fills. The suggestion list is an ARIA combobox.
WCAG 2.2 · 1.3.5 identify input purpose, 3.3.7; postal-format conventions (UPU); Baymard address research.
Core · Settings
Appearance Switcher
Light, dark, or follow the system — with the system as the default, because the user already told their OS what they want and asking twice is a bug.
A three-option segmented control in settings (and optionally a topbar shortcut). "Auto" tracks the OS live, including scheduled sunset switching, and says that's what it does.
Never dark-only as a brand statement for a reading-heavy product; never flash the wrong theme on load (persist the choice where first paint can read it). Don't ship a toggle that fights the OS.
The switch applies instantly, announces, and respects prefers-contrast and forced-colors beyond the binary. Both themes hold the same AA contrast contract — dark mode is not an excuse.
HIG dark mode; Material color schemes; WCAG 2.2 · 1.4.3 (both themes), prefers-color-scheme.
Core · Settings
Language & Region
Every language names itself in itself — 日本語, not "Japanese" — because the person who needs the switch is precisely the one who can't read your current language.
Settings, and reachable from onboarding. Language and region are separate choices (English · Japan is a real life); currency and units follow region with a manual override.
Never a flag for a language — flags are countries, and Spanish has twenty. Never IP-force a locale the user changed away from; the explicit choice always outranks geolocation.
Each option carries its own lang attribute so screen readers pronounce it natively; switching announces in the new language; layout survives RTL and 35%-longer German strings.
WCAG 2.2 · 3.1.2 language of parts; BCP 47; HIG internationalization; W3C i18n best practices.
Text Animations
Split Reveal
The headline arrives one character at a time — a stagger so short it reads as texture, not theatre. The workhorse entrance for hero copy.
Hero and section headlines, once per view, on first reveal. Total duration stays under 700ms — the reader came for the sentence, not the choreography.
Never on body copy or anything the user must read urgently (errors, prices, legal). Never re-trigger on every scroll pass — an entrance happens once.
The real sentence lives in the element's aria-label; animated characters are aria-hidden — a screen reader hears one sentence, never letter soup. Space is reserved: zero layout shift. Reduced motion renders the final state instantly.
WCAG 2.2 · 2.3.3 animation from interactions; Core Web Vitals CLS discipline; HIG Motion (purposeful, brief).
Text Animations
Blur In
Words resolve from soft focus to sharp, like the eye settling. The gentlest entrance in the set — calm products earn it.
Editorial intros, wellbeing and premium surfaces, word-level stagger (never per character — blur reads at word scale). Pairs with slow content like photography.
Not on data or numbers — blurred digits read as wrong digits for a frame. Not on low-power devices at long lengths: blur is a filter, and filters cost frames.
Same screen-reader contract as Split Reveal (real text in aria-label, animation aria-hidden). Blur animates filter only — no movement, so it's the safest choice for vestibular-motion sensitivity short of none.
WCAG 2.2 · 2.3.3; vestibular-safe motion guidance (filter over transform); HIG Motion.
Text Animations
Typewriter
Text that appears to be written, caret and all. Fifty years old and still the most honest way to say "something is composing this."
Short phrases where authorship is the message — an AI drafting, a terminal, a search suggestion. One line, under 60 characters, then the caret stops blinking and rests.
Never for paragraphs — nobody watches 400 characters get typed. Never as fake AI theatre on content that arrived instantly (see AI Disclosure: pretending to compose is a small lie with a big pattern).
The full string is exposed to assistive tech immediately (aria-label) — the typing is visual only, never a reading-speed gate. The caret blink stops at rest (nothing blinks forever), and reduced motion prints the line whole.
WCAG 2.2 · 2.2.2 (nothing blinks indefinitely), 2.3.3; EU AI Act Art 50 adjacency (composition theatre must be truthful).
Text Animations
Decode
Characters churn through noise and settle into the message, left to right. The cyberpunk entrance — loud, memorable, and strictly rationed.
One moment per product: a reveal, an unlock, a launch. Settle direction is always left-to-right so the eye can start reading before the animation finishes.
Never on numbers users act on (a churning price is a slot machine), never on security codes (churn reads as tampering), and never twice on the same screen.
Assistive tech gets the final string only — the noise frames are never announced. Fixed-width character cells prevent reflow during churn. Total under 900ms; reduced motion skips straight to the message.
WCAG 2.2 · 2.3.3, 4.1.3 (announce once, final only); Core Web Vitals CLS.
Text Animations
Count Up
Numbers that travel to their value. Movement says "this was measured, watch it arrive" — which is exactly why it may only ever land on the true figure.
Stats, milestones, totals — once, on first view, easing out so the last digits are readable. Tabular numerals so nothing jitters horizontally.
Never animate money the user is about to pay (the total is a fact, not a performance), and never count to a rounded marketing number the data doesn't support — motion amplifies the claim.
The final value is in the accessible name from frame zero; intermediate values are visual only. Width is reserved for the final figure — no shift. Reduced motion shows the number, done.
WCAG 2.2 · 2.3.3, 4.1.3; FTC substantiation discipline (motion is emphasis — emphasised claims need evidence).
Text Animations
Word Rotate
One slot in the sentence cycles through alternatives — "built for runners / riders / climbers". The rotation makes a list feel like a welcome.
Hero taglines where the product genuinely serves every word in the list. Three to five words, each readable for ≥1.8s, and the cycle ends — three loops, then it rests on the primary word.
Never rotate words users might need to reference ("free" appearing every third cycle is a rotating claim), and never in body text — moving targets punish readers mid-sentence.
The accessible sentence names all variants once ("built for runners, riders, and climbers") instead of announcing every swap. The slot reserves the widest word — no reflow. Stops within five seconds, which is the actual 2.2.2 exception — a cycle count is not one, and three rotations usually exceed five seconds. Instantly at rest under reduced motion.
WCAG 2.2 · 2.2.2 pause/stop/hide (self-stopping), 2.3.3; FTC (rotating claims are still claims).
Text Animations
Gradient Flow
A slow aurora inside the letterforms. Color moves so the type doesn't have to — the quietest way to make one line feel alive.
One brand moment per screen — the hero word, a plan name, a launch title. The drift is slow (≥8s per pass) and the gradient's darkest stop still meets contrast on its background.
Never on interactive labels (a shifting button label reads as a state change) and never on more than one element per view — two auroras compete, and both lose.
Pure background-position animation — the glyphs never move, so it's vestibular-safe. Every gradient stop holds ≥4.5:1 against the surface; reduced motion freezes the gradient (color stays, drift stops).
WCAG 2.2 · 1.4.3 (every stop passes), 2.3.3; HIG color (decorative color never carries meaning).
Text Animations
Shine Sweep
A highlight passes across the word once, like light across brushed metal. The premium accent — and like all premium things, scarce by design.
Achievement names, tier labels (Gold, Pro), unlocked states — one sweep on reveal, optionally one on hover. The sweep is the reward's punctuation, not its substance.
Never looping — a permanently shimmering word reads as an ad and burns the effect for the real moment. Never on discount or urgency copy; shine is celebration, not pressure.
The base text is fully readable before, during, and after the sweep — the highlight adds, never subtracts, contrast. One-shot with a replay affordance; nothing under reduced motion.
WCAG 2.2 · 1.4.3 (base state passes alone), 2.3.3; EU DSA Art 25 (no shimmer-as-urgency).
Text Animations
Wave
Characters take turns bouncing — playful energy for playful products. The party trick of the set, which is precisely why it self-stops.
Celebration and kids-adjacent surfaces: "You did it!", loading mascots, empty-state charm. Short words, small amplitude (≤0.18em), three passes, done.
Nowhere serious — a waving "Payment failed" is a tonal catastrophe. Not while the user reads adjacent content; bouncing in the periphery is distraction, not delight.
Self-terminates within the five seconds 2.2.2 allows — the exception is a time limit, not a pass count; per-character transform only, layout space reserved. Reduced motion: still text, full stop — charm is optional, reading isn't.
WCAG 2.2 · 2.2.2 (self-stopping), 2.3.3; UK Age Appropriate Design Code adjacency (kid surfaces avoid compulsive motion).
Text Animations
Marquee Ticker
The infinite ribbon — logos, headlines, drop announcements. The only permanently moving text this system allows, and it pays for the privilege with a real pause control.
Peripheral, skimmable, repeating content: partner logos, "as seen in", event tickers. Slow enough to read (≥12s per loop), duplicated seamlessly, edges faded.
Never for content users must not miss — motion is the opposite of guaranteed delivery. Never faster to create urgency, and never two tickers on one screen.
WCAG 2.2.2 in full: moving >5s means a visible pause button, plus hover and focus both pause. The duplicate strip is aria-hidden; the content is also available as a static list to assistive tech. Reduced motion parks it as a scrollable row.
WCAG 2.2 · 2.2.2 pause/stop/hide (the letter of it), 2.3.3; HIG Motion.
Data & Tables
Tree View
Hierarchy you can walk with four arrow keys. The canonical pattern for folders, categories, and settings trees — one tab stop, not forty.
Nested structures the user browses and picks from: file trees, category managers, org settings. Depth is real and parents are meaningful groupings, not decoration.
Flat lists dressed as trees — if everything sits at level one, use a list. And never for primary navigation on mobile: a drill-in list per screen beats a tiny tree.
ARIA tree pattern: one tab stop with roving focus; ↑↓ move, → expands or enters, ← collapses or exits, Home/End jump. Every branch carries aria-expanded and aria-level; the whole tree is useless if only the mouse can open it.
WAI-ARIA APG tree view pattern; WCAG 2.2 · 2.1.1 keyboard, 4.1.2 name/role/value.
- ▸📁design-system
- ▸📁tokens
- 📄color.json
- 📄type.json
- ▸📁components
- 📄button.md
- 📄table.md
- 📄AGENTS.md
- ▸📁tokens
Click a row or focus the tree and drive it with ↑ ↓ → ← · Home · End.
Data & Tables
Selection Tree
Checkboxes with a parent that tells the truth: fully checked, fully clear, or honestly mixed. Selecting a branch selects its children — and says so.
Bulk selection over a hierarchy — permission sets, folder sync, category filters — where "select the parent" legitimately means "select everything inside".
When children carry different consequences (billing vs. deletion), don’t hide them behind a parent toggle: one careless click should never quietly select something expensive or destructive.
Parent checkboxes expose three real states; the mixed state is aria-checked="mixed", never a styling trick. Checking a parent checks all descendants; un-checking one child drops the parent to mixed immediately. A live count announces the running total.
WAI-ARIA APG checkbox pattern (tri-state); WCAG 2.2 · 4.1.2 name/role/value, 4.1.3 status messages.
0 of 3 permissions selected
Data & Tables
Tree Table
Hierarchy inside a real table: parent rows expand, indent carries the level, and the parent’s numbers equal the sum of its children — a rollup that doesn’t reconcile is a lie in a grid.
Budgets, storage usage, org rollups — tabular data where rows have children and the parent aggregates them. The user needs both the total and the breakdown.
Arbitrary grouping the user didn’t ask for. If the hierarchy is only two levels and always expanded, plain visual grouping with subheader rows is simpler and calmer.
A real <table>; expandable rows carry aria-expanded and indentation encodes aria-level. Rollup cells are computed from child rows in one place, so the parent can never drift from its children. Expand state is announced, not just drawn.
WAI-ARIA APG treegrid pattern; WCAG 2.2 · 1.3.1 info & relationships.
| Team | Seats | Spend / mo |
|---|---|---|
| — | — | |
| Product design | 6 | $720 |
| Brand studio | 3 | $360 |
| Research | 2 | $240 |
The parent row is computed from the children on load — expand to check the math.
Data & Tables
Editable Cells
A grid you can type into without fear: Enter commits, Escape restores, bad input explains itself in place — and every edited cell wears a mark until it’s saved.
High-volume numeric corrections — budgets, quantities, forecasts — where a form-per-row would take ten times as long and the user lives in spreadsheets anyway.
One-off edits of complex records (open a form), or anything destructive. And never auto-commit on blur alone for consequential values — a stray click should not silently change a number.
Cells are buttons until activated (click or Enter), then a labelled input. Enter commits, Escape cancels and restores the previous value, invalid input keeps focus with an inline message. Edited cells carry a visible dot and an "edited" text flag — colour is never the only signal.
WAI-ARIA APG grid pattern (editable); WCAG 2.2 · 3.3.1 error identification, 3.3.3 error suggestion, 1.4.1 use of color.
| Line item | Budget (USD) |
|---|---|
| Research incentives | |
| Usability tooling | |
| Type licences |
Enter commits · Esc restores · letters are refused with a reason.
Data & Tables
Table Pagination
"Showing 11–20 of 47" — a table that tells you where you are and how much is left. The honest counter is the component.
Bounded result sets the user scans and returns to — orders, invoices, tickets. Pagination gives position, a stable URL per page, and a reachable footer.
Feeds designed for drift (that’s the infinite-scroll entry, with its own honesty rules), or under ~20 rows — just show them all; a pager on one page of data is ceremony.
The range line is a live region and always exact — never "lots" or "1000+" when the system knows the number. Previous/Next disable honestly at the ends instead of hiding. Page size changes keep the current first row visible, not reset to page one.
WCAG 2.2 · 2.4.8 location, 4.1.3 status messages; honest counts per FTC deception standards (no invented totals).
| Order | Status | Total |
|---|
Data & Tables
Column Manager
Let the reader shape the table — show, hide, and keep what matters. Hiding a column hides ink, never data: the export still carries everything.
Wide operational tables where different roles read different columns. The user’s choice persists, so Tuesday’s table looks like Monday’s.
Tables under five columns (the manager costs more than it saves), or as a way to bury a column users need for an honest read — hiding the "fees" column by default is a dark pattern wearing a feature’s clothes.
A disclosure lists every column as a real checkbox; at least one column stays on — the control refuses to empty the table. Changes announce "column hidden/shown" and headers stay in a real <th> structure for screen readers.
WCAG 2.2 · 1.3.2 meaningful sequence, 1.3.1 info & relationships; FTC dark-pattern guidance (no burying material facts).
| Order | Status | Region | Total |
|---|---|---|---|
| #3021 | Shipped | EU | $182 |
| #3022 | Packed | US | $96 |
| #3023 | Shipped | JP | $240 |
Hidden means hidden from view — exports still include every column.
Data & Tables
CSV Export
One click, and the user owns their data — with the export honestly declaring whether it’s the filtered view or everything.
Any table the user might reasonably take elsewhere: transactions, contacts, usage. Portability is a right in consumer products, not a premium feature.
Never as a paywall for the user’s own records, and never exporting silently more than the screen showed (hidden PII "coming along for the ride") without saying so.
Two labelled actions — "Export view" and "Export all" — each states its row count before the click. The file is generated client-side, named with the date, and completion is announced. What you were told is exactly what lands in the file.
GDPR Art. 20 data portability; WCAG 2.2 · 4.1.3 status messages.
CSV is built client-side and downloads immediately.
Data & Tables
Table States
Loading, empty, error, loaded — four truths, one silhouette. The table’s frame never moves while its story changes.
Every asynchronous table. The skeleton reserves the exact geometry; empty explains and offers one action; error says what failed and offers retry.
Skeletons for instant local data (a flash of fake loading erodes trust), and never an empty state that blames the user or an error state that says only "something went wrong".
The region is aria-busy while loading and announces each arrival once (WCAG 4.1.3) — a screen reader hears "12 orders loaded", not a spinner. All four states share one fixed-height frame: zero layout shift. Retry is a real button, focus lands on it.
WCAG 2.2 · 4.1.3 status messages, 2.4.3 focus order; Core Web Vitals CLS discipline.
Data & Tables
Sparkline Cells
A trend at reading speed — and an axis that tells the truth. Toggle the cropped version to watch honest data become theatre.
Dense monitoring tables where direction matters more than magnitude: uptime, spend, engagement. The sparkline is a glance; the number is the fact.
As the only representation of a value (a sparkline without its number is decoration), or with a cropped axis that manufactures drama out of a 2% wiggle.
Every sparkline sits beside its current value and a direction word — the image is aria-hidden, the text carries the meaning (WCAG 1.1.1). The y-axis baseline is honest by default; any zoomed axis must be labelled as such. Rendered as inline SVG, no canvas tax.
WCAG 2.2 · 1.1.1 non-text content, 1.4.1 use of color; FTC substantiation — a chart is a claim.
| Metric | Trend | Now |
|---|---|---|
| Uptime | 99.7% · steady | |
| Support load | 22/day · falling |
Same numbers, different axis. The cropped view is labelled — because it is a different claim.
Data & Tables
Comparison Table
Plans side by side with a first column that never scrolls away and marks that read in grayscale. A comparison is a promise matrix — every cell is a claim.
Pricing pages and feature matrices where the user genuinely chooses between tiers. Pick a column to hold it highlighted while you read down.
Never against competitors with cells you can’t substantiate, and never a "recommended" column that’s just the most expensive one wearing a halo — that’s FTC territory, not persuasion.
A real <table> with scope-correct headers; the plan column is sticky so rows stay legible on scroll. Included/not is double-encoded — ✓ plus the word, — plus the word — colour never carries it alone. Selecting a plan highlights the column and announces it.
WCAG 2.2 · 1.4.1 use of color, 1.3.1 info & relationships; FTC deceptive-comparison and substantiation standards.
| Feature | |||
|---|---|---|---|
| Projects | 3 | 20 | Unlimited |
| Export | ✓ yes | ✓ yes | ✓ yes |
| Audit log | — no | — no | ✓ yes |
| Price / mo | $0 | $12 | $29 |
Plus selected. Marks are glyph + word — the table survives grayscale.
Product & Metrics
DAU / MAU KPI Card
The numbers a product team wakes up to — with the comparison window named, the delta in words, and no axis tricks. A KPI card is a claim with a decimal point.
Team dashboards and exec views where daily and monthly active users drive decisions. The card states its window ("vs. previous 7 days"), its timezone basis, and its direction in words.
Public marketing surfaces without substantiation — a KPI card that rounds 41.2K up to "50K users" is an advertising claim, not a dashboard. And never a delta without its window: "+12%" against nothing is theatre.
Value, delta and window are one accessible sentence ("DAU 41,280, up 4.2% versus the previous 7 days") — the arrow is aria-hidden decoration. Direction is encoded by word and glyph, never colour alone. Numbers are tabular; the card never reflows as digits change.
WCAG 2.2 · 1.4.1 use of color, 1.1.1 non-text content; FTC substantiation for any externally published figure.
Window: trailing 7 days, UTC. "Active" = performed a core action (defined below, not just an app open).
Product & Metrics
Stickiness Ratio
DAU / MAU with the part everyone hides: what "active" means. Change the definition and watch the same product tell a different story — the definition is the metric.
Product health reviews where frequency of genuine use matters. The ratio ships with its activity definition printed beside it, so two teams can never quote two different "stickiness" numbers from the same data.
As a vanity comparison across products with different definitions of active — a meditation app and a banking app have structurally different honest ceilings. And never as a target detached from value ("raise DAU/MAU" is how streak-abuse gets designed).
The ratio, the window, and the definition of "active" render as one unit — the definition is not a tooltip, it is part of the number. Changing the definition re-computes the ratio and announces it. The gauge is aria-hidden; the sentence carries the value.
GDPR Art. 5(1)(c) data minimisation (measure what you need, define what you measure); WCAG 2.2 · 1.1.1, 4.1.3 status messages.
13.2% DAU / MAU · trailing 28 days · active = performed a core action
Same product, same month. Loosen the definition and stickiness "improves" without a single user behaving differently — which is why the definition ships with the number.
Product & Metrics
Retention Cohort Grid
Weekly cohorts against weeks-since-signup — the table that tells you whether the product keeps anyone. Shade helps scanning; the printed percentage carries the truth.
Retention reviews and activation experiments. Each row is a signup cohort; each cell prints its percentage — the heat shading is an accelerator, never the message.
Cohorts too young to read (a 1-week-old cohort has no week-4 story — show an em dash, not a hopeful blank), and never extrapolated forward: a cohort grid is history, not a forecast.
A real <table> with scope-correct headers; every cell prints its value so grayscale, print, and screen readers get identical truth (WCAG 1.4.1). Unknown future cells render "—" with an accessible "not yet measurable". Shading is background-only and passes contrast against its printed text.
WCAG 2.2 · 1.4.1 use of color, 1.3.1 info & relationships; honest-baseline discipline — an empty cell is unknown, not zero.
| Cohort | W0 | W1 | W2 | W3 | W4 |
|---|---|---|---|---|---|
| Jun 15 | 100% | 46% | 34% | 29% | 27% |
| Jun 22 | 100% | 48% | 36% | 31% | — |
| Jun 29 | 100% | 52% | 38% | — | — |
| Jul 6 | 100% | 51% | — | — | — |
Shading accelerates the scan; the printed number is the record. "—" means not yet measurable — never zero, never projected.
Product & Metrics
Activation Funnel
Visited → signed up → activated → retained, with absolute counts and honest step percentages — and a toggle that shows why "% of previous step" and "% of top" tell different stories.
Growth reviews and onboarding experiments. Every bar carries its absolute count; percentages state their base ("of previous step" vs. "of visitors") because the base is half the claim.
Never present a step-percentage as an overall conversion — "80% activation" that is really 80% of the 4% who signed up is how funnels lie. And no smoothed or idealised bars: the funnel is the data, not the aspiration.
Bars are aria-hidden; a list of real numbers carries the meaning. The percentage base is printed on the toggle and announced when switched. Counts are exact — a funnel that says "~10K" when the system knows 9,412 is rounding toward a story.
FTC substantiation (a conversion claim is a claim); WCAG 2.2 · 1.1.1 non-text content, 4.1.3 status messages.
Base: each percentage is measured against the previous step.
Product & Metrics
Annotated Metric Chart
A DAU line with its causes pinned to it — releases, incidents, campaigns. A spike without its annotation is a story half-told; worse, it gets retold wrong.
Any metric chart a team will discuss later. Releases, incidents and campaigns are pinned at their dates so the chart carries its own context into every screenshot and slide.
Never annotate selectively — pinning the release before every rise but omitting the outage before every dip curates a fiction. If annotations exist, they are complete for the window shown.
Annotations are markers plus a real text list below the chart — the list, not the hover, is the accessible record. The line is aria-hidden; a summary sentence states start, end, and the named events. Marker shapes differ by type; colour never carries it alone.
WCAG 2.2 · 1.1.1, 1.4.1; SEC 17a-4-adjacent record honesty for anything a team will audit later — the chart is the minutes of the meeting.
- Jul 2 · v2.4 release — onboarding rebuilt; DAU +9% over the following week.
- Jul 10 · 4-hour outage — auth provider incident; the dip is the outage, not the release.
The list is the record — complete for the window, incidents included. Curated annotations are curated truth.
Product & Metrics
Now / Next / Later Board
A roadmap that promises sequence, not dates. "Later" has no quarter attached — a date you can't keep is a promise you shouldn't print.
Public and internal roadmaps where priorities are real but dates would be guesses. Three honest buckets: building now, next in line, on the horizon — each item carries its problem statement, not a feature codename.
When a commitment is contractual (enterprise deliverables have dates and belong in a timeline, not a mood board), or as a wish list — a Later column with forty items is a backlog wearing a roadmap's clothes.
Columns are real lists with headings; order within a column is meaningful and stated. Items link to their explanation. Moving an item between buckets is a public event (see the changelog entry), not a quiet edit — roadmap history is part of the roadmap.
FTC forward-looking claims discipline (a public roadmap is a representation); WCAG 2.2 · 1.3.1 info & relationships.
Now
Next
Later
Select an item for its status note. Later items carry no dates — sequence is the promise, not the calendar.
Product & Metrics
Confidence Timeline
Quarters on the x-axis, honesty on every bar: committed, planned, and exploring are three different promises — encoded by pattern and word, not just colour.
Roadmaps that genuinely need dates — enterprise commitments, platform deprecations, compliance deadlines. Each bar states its confidence class, and only "committed" reads as a promise.
Never paint "exploring" the same solidity as "committed" and let distance on the x-axis do the hedging — a Q4 bar drawn solid is read as a promise regardless of the legend. And never delete slipped bars: reschedule them visibly.
Confidence is triple-encoded: fill pattern (solid / hatched / outline), a printed word on the bar, and position in the legend. Each bar is a list item to assistive tech ("Shared spaces — planned, Q4 2026"). Slips render as a strikethrough date plus the new one, never a silent move.
FTC forward-looking representations; WCAG 2.2 · 1.4.1 use of color, 1.3.1.
- Offline mode — committed · Q3 2026 (contractual for enterprise)
- Shared spaces — planned · Q4 2026 (date is intent, not contract)
- Public API — exploring · 2027 (direction only; solid bars are earned)
Product & Metrics
Public Changelog
Shipped, dated, append-only. The changelog is the roadmap's receipts — the one page where the product can't exaggerate, because the feature is either there or it isn't.
Every product with a public roadmap: each shipped item gets a dated entry linking to the feature, written in outcome language ("you can now export…"), including honest entries for fixes and rollbacks.
Never edit history — a changelog whose old entries quietly improve is marketing wearing an archive's clothes. And no "improvements and bug fixes" filler: if it's worth an entry, it's worth a sentence.
Entries are an ordered list with real <time datetime> stamps, newest first. Rollbacks and regressions get entries too — the record includes the walk-backs. Anchors per entry make every change citable.
Append-only record discipline; WCAG 2.2 · 1.3.1; consumer-protection truthfulness for shipped-feature claims.
-
Data export shipped — you can now download every record as CSV from Settings. (GDPR Art. 20 in the wild.)
-
Rolled back: smart sort — it reordered lists people had memorised. Reverted while we rethink it; your order is yours again.
-
Offline mode in beta — 10% of users, opt-in. Known gap: attachments don't sync yet.
Append-only, rollbacks included. A changelog that only ever ships wins is a brochure.
Product & Metrics
Feature Request Board
Upvotes with an honest ending: under review, planned, or declined with a reason. Declining honestly beats ghosting — a board where nothing is ever refused is a suggestion box with a hole in the bottom.
Products that genuinely let user demand shape priority. Every request has a status; "declined" states why; "planned" links to the roadmap bucket it landed in.
Never as engagement theatre — if votes don't influence anything, the board is a dark pattern harvesting hope. And votes are one input, not a referendum: the loudest cohort is not the whole market, and the board says so.
Vote buttons are real toggles with aria-pressed and a live count; one vote per account, reversible. Status is a word + glyph, filterable. The "how we decide" note is part of the component, not a help-centre footnote.
FTC dark-pattern guidance (no fake participation); WCAG 2.2 · 4.1.2 name/role/value, 4.1.3.
Votes are an input, not a referendum — the decision note ships with every status change.
Product & Metrics
Staged Rollout Status
Beta at 10%, expanding to 100% — with who's in the cohort, what's not done yet, and a visible way out. A rollout indicator is informed consent for unfinished software.
Feature flags and progressive releases that real users can see. The status names the stage, the percentage, the known gaps, and how to opt out (or in) while the flag is live.
Never use "beta" as a liability shield for a finished-and-charged feature, and never roll a cohort forward silently after telling users they could opt out — the exit must survive the expansion.
Stage, percentage and known-gaps render as text, not just a progress bar (the bar is aria-hidden). Opt-out is a real control adjacent to the status, and the choice persists. Expansion steps are announced and dated — see the changelog entry pattern.
App Store Review 2.2 (beta labelling); WCAG 2.2 · 1.1.1, 4.1.2; FTC — "beta" is a disclosure, not a disclaimer.
Stage 1 of 3 · 10% cohort (opt-in) · known gap: attachments don't sync. Next expansion is dated and announced, never silent.
Start · Skills Kit
Skills that speak this system.
One hundred and nineteen downloadable Markdown skills for the people — and agents — who build with this catalogue, from screen composition to Dify workflow planning and generative-media pipelines. Unlike the institutional sibling's forty-skill general set, every one of these is CDS-native: it reads the machine contracts, cites the registers, and enforces the hard rules. Load one into any assistant and the assistant works the way this system works. Both kits — all 160 files — are browsable in one place at the AI Skills Library.
How these fit. A skill here is a working method bound to this system's contracts — each references components.json, tokens.json and AGENTS.md, so the method and the machine layer can't disagree. Plain Markdown: paste into any assistant, load as a Claude skill, or serve to a local model — vendor-neutral by construction. Where a skill touches law (the dark-pattern audit, AI surfaces), it says plainly that it finds design-level issues and routes legal questions to counsel. The institutional sibling's 40-skill set covers the general domains; these hundred and nineteen are the specialists — for this catalogue, for the AI tools you already run, and for the craft of design itself.
Organizational Memory Architect
Decision archaeology for a whole company: tickets, epics, chat, version history and release records distilled into a cited, role-scoped institutional memory — documented vs. inferred labelled, veterans confirm, InfoSec gate first, maintained by delta. Knowledge that survives attrition.
organizational-memory-architect.mdScreen Composer
Brief → screen, from the catalogue: selection, bundles, hard rules, token slice, human sign-off — the seven-step read path as a working method.
cds-screen-composer.mdComponent Author
Add a component the way the existing 190 were built — register before markup, tokens only, delegated events, reduced-motion contract, real anchor.
cds-component-author.mdDesign Review
Crit and PR review where feedback carries a citation — every finding maps to an entry URL or rule id; blocks distinguished from opinions.
cds-design-review.mdDark-Pattern Audit
Walk the money, the exit, the consent, and the pressure — findings a regulator would recognise, each paired with the honest alternative from the catalogue.
cds-dark-pattern-audit.mdAccessibility Verification
The consumer-specific WCAG 2.2 pass: targets, reduced motion, live regions, keyboard walks — verified against each component's own contract cell.
cds-a11y-verification.mdUX Writing
The words carry the same contract as the components: the error formula, outcome-named buttons, symmetric consent language, zero guilt anywhere.
cds-ux-writing.mdMotion Choreography
One spring, three durations, self-terminating loops — including the Text Animations domain's binding usage limits and the reduced-motion rendering mode.
cds-motion-choreography.mdToken & Theming
Rebrand and extend without breaking the API — values change, names don't; themes move in lock-step; AA is part of the token, verified per theme.
cds-token-theming.mdFramework Port
React, SwiftUI, Compose — the deliverable is contract parity, not pixel worship: the register travels, tokens map, accessibility survives the translation.
cds-framework-port.mdAI Surface Kit
Sequence the 22-entry AI domain into a coherent feature: disclosure → grants → streaming → grounding → gates → traces → honest memory. Human signs.
cds-ai-surface-kit.mdProduct Design Kit
Analyse any product surface into a tokenized Design Kit document — YAML tokens, {token.ref} component specs, falsifiable don'ts, and a mandatory Known Gaps section.
cds-product-design-kit.md
dev · productDify Workflow Planner
Plan LLM apps on dify.ai before touching a node — contract paragraph, three-lane graphs, model routing by node, RAG as a supply chain, human gates on the irreversible.
dify-workflow-planner.md
designer · devComfyUI Pipeline Architect
Node graphs as production pipelines — five planned stages, pinned seeds and versions, VRAM budgets, workflow JSON in version control, licenses checked before commercial use.
comfyui-pipeline-architect.mdGenerative Image Direction
Direct generation like a photographer with a brief — stable prompt structure, style systems for brand consistency, and binding honesty rules: synthetic never masquerades as evidence.
generative-image-direction.mdGenerative Video Direction
Storyboard first, one shot one job, consistency locks, cut to hide the seams — and never present synthetic footage as recorded reality. Disclosure per destination platform.
generative-video-direction.mdAI Asset Integration
Goods-inwards for generated media — provenance intake, license verdicts, C2PA that survives the CDN, versioning like code, and the CDS disclosure surfaces that present it honestly.
ai-asset-integration.md
developer · QAn8n Test Automation
Turn n8n into a standing test harness — scheduled smoke tests, schema-asserting HTTP checks, loud specific alerts, and the workflow JSON in version control.
n8n-test-automation.md
developer · opsOllama Local Deploy & VRAM Advisor
Stand up Ollama in Docker, then pick the model your GPU can actually run — a VRAM-first sizing method (params × quant + KV) with a recommendation per memory tier.
ollama-local-deployment.md
developerHermes Agent Orchestration
Run a Hermes-family open-weight model as an agent’s reasoning core — typed tool schemas, validated structured calls, an allowlist, and a human on every irreversible action.
hermes-agent-orchestration.md
developer · opsOpenClaw Web Automation
Operate a computer-use agent safely — allowlisted targets, no credentials handed over, page content treated as data not instructions, human gates on every irreversible click.
openclaw-web-automation.md
writer · everyoneMonica Assistant Workflow
Get trustworthy work out of an all-in-one assistant — bring real context, edit the draft, verify every fact, keep sensitive data out of the box.
monica-assistant-workflow.md
developerOpenCode Terminal Agent
Drive a terminal coding agent well — one bounded task, plan before edit, read every diff, tests as the acceptance gate, least-privilege on a branch.
opencode-terminal-agent.md
developerCline VS Code Agent
Use Cline’s Plan-then-Act as a real checkpoint, approve edits deliberately, and wire MCP at a live contract so it builds to a system it can be refused by.
cline-vscode-agent.md
ML · opsHugging Face Model Ops
Ship open models like an engineer — read the card before the weights, verify the licence before commercial use, pin the revision, prefer safetensors, match serving to load.
huggingface-model-ops.md
developer · platformAWS Cloud Architect
Build and operate AWS with an agent — IaC with a reviewed plan, least-privilege IAM, private-by-default storage, cost budgets with alarms, Well-Architected, and a human on every destroy.
aws-cloud-architect.md
developer · mobileFirebase Backend Ops
Maintain a Firebase backend safely — security rules first and Emulator-tested, App Check on real clients, idempotent Functions, read/write cost alarms, human-gated production rule changes.
firebase-backend-ops.md
developer · platformGitHub Repo Orchestration
Run a repo like an org — PR-first, CI as the merge gate, protected main, CODEOWNERS review, fine-grained tokens, secret scanning, SHA-pinned Actions, environment-gated deploys.
github-repo-orchestration.md
developer · QAGoogle Jules QA Planner
Delegate to an async coding agent and get reviewable PRs — spec the task, approve the plan, parallelize independent work, tests as the gate, and turn every edge case into a committed test.
google-jules-qa-planner.md
product · PMJira Project Orchestration
Run delivery in Jira as a disciplined PM — stories with testable acceptance criteria, capacity-honest sprints, JQL that surfaces risk, human-owned status transitions, tickets linked to evidence.
jira-project-orchestration.md
ops · teamSlack Ops Automation
Wire Slack as the ops nervous system without noise — specific actionable alerts, severity routing, self-assembling incident channels, in-channel approvals gated on a human click.
slack-ops-automation.md
developerVS Code Agent Workspace
Turn VS Code into an agent cockpit — runnable tasks/debug, MCP wired to a real contract, every diff reviewed, Workspace Trust gating untrusted folders, destructive commands human-gated.
vscode-agent-workspace.md
developer · platformCloudflare Edge Platform
Ship and defend at the edge — Workers/Pages via previews, storage matched to access, surgical cache purges, tested WAF, Zero-Trust internal access, and DNS changes gated because they go global in seconds.
cloudflare-edge-platform.md
everyone · researchPerplexity Research
Use a citation-first answer engine as a research accelerator — follow citations to primary sources, separate grounded from synthesized, verify anything you ship, keep sensitive queries out.
perplexity-research.md
research · everyoneNotebookLM Source Curation
For an industry or domain, curate the sources worth grounding on — highest-authority URLs, peer-reviewed papers, and official first-party datasets — each scored for authority and date.
notebooklm-source-curation.md
developer · MLNVIDIA CUDA GPU Optimization
Read the real NVIDIA hardware and size GPU rendering + VRAM budgets to fit — precision, batch, headroom — so the workload runs fully on the GPU instead of OOM-ing or spilling to CPU.
nvidia-cuda-gpu-optimization.md
designerGraphic Design Award Research
Find award-winning graphic design from the last five years (The One Show, D&AD, TDC), verify each winner against the official archive, and dissect the philosophy and the design logic that won.
graphic-design-award-research.md
designer · devAwwwards Site Analysis
Analyse Awwwards SOTD/SOTM winners — design difficulty and build difficulty rated separately (★1–5), inferred tech stack, jury criteria, and 3–5 competitor sites anchored to your project.
awwwards-site-analysis.md
designer · devFWA Award Analysis
Mine The FWA for cutting-edge interactive work — design and build difficulty on ★1–5, inferred stack, what is genuinely innovative, and 3–5 peer sites anchored to what you are building.
fwa-award-analysis.md
design-system leadDesign System Analysis
An objective read of a design system — no hype, no hate, only facts. Ed Chen’s lens: separate fact from judgment, reconstruct the build logic and context, anchored to what you are trying to achieve.
design-system-analysis.md
growth · dataSEO & GEO Self-Audit
Turn your own site’s traffic into an honest SEO + GEO plan: fold out your own dev/QA visits, split bots from humans, read the real timezone and referrer signals, then strengthen search ranking and AI-answer discoverability.
seo-geo-self-audit.md
designer · devMaterial Design Adoption
Decide whether Material 3 fits before adopting it, then deploy it coherently — tokens, components, elevation, motion — so the whole system is used as one, not half-applied and drifting.
material-design-adoption.md
designer · devAnt Design Adoption
Decide whether Ant Design fits a data-dense product, then deploy it on-system: seed/map/alias tokens, ConfigProvider theming, components before custom, adherence checks against drift.
ant-design-adoption.md
designer · devApple HIG Adherence
Keep an Apple-platform product on the HIG rails: enforce the non-negotiables, earn a premium feel through restraint and native conventions, and protect performance and App Store review readiness.
apple-hig-adherence.md
data · growthGoogle Analytics (GA4)
Set up GA4 to answer real decisions, not collect vanity metrics: a measurement plan, consent-aware collection, bot and self-traffic filtering, and honest reading of attribution and sampling.
google-analytics.md
product · PMTrello Project Flow
Turn a Trello board into a delivery system: lists that model the real workflow, cards with owners and a definition of done, honest WIP, and Butler automation that never fakes progress.
trello-project-flow.md
product · docsConfluence Knowledge Base
Build a Confluence space people find and trust: architecture that matches how the team searches, templates that make good docs the default, one source of truth per topic, and a rhythm that fights rot.
confluence-knowledge-base.md
backend · dataMySQL Backend
Design and run MySQL that stays correct and safe: schema from access patterns, indexes for real queries, parameterised access, least privilege, and backup-first, human-gated destructive operations.
mysql-backend.md
data · platformDatabricks Lakehouse
Build governed, cost-controlled pipelines on Databricks: medallion + Delta, idempotent jobs with real failure handling, Unity Catalog governance and PII protection, and human-gated irreversible operations.
databricks-lakehouse.md
bot · devTelegram Bot Development
Take a Telegram bot from idea to listed product: Bot API surface, webhook vs long-polling, clean state and data, locale/language adaptation, rate-limit and error handling, and an architecture built for expansion and stability.
telegram-bot-development.md
bot · devDiscord Bot Development
Build a complete Discord bot end to end: slash-command and component design, least-privilege intents and permissions, safe moderation, rate-limit and gateway handling, and a deployment architected for growth.
discord-bot-development.md
product · thinkingNotion Thinking Assistant
Use Notion as a structured thinking partner: externalise the reasoning into a shape a person and an agent both work in — the agent structures, drafts, and flags gaps while the human keeps the decision and the sign-off.
notion-thinking-assistant.md
fintech · securityDigital Wallet Architecture
Reason through a wallet before it touches real value: threat model, key management, encryption, signing integrity, and the honest limits of what software guarantees. A design method with security humility — not a guarantee; a professional audit is required before real funds.
digital-wallets-architecture.md
ops · dataDatadog Observability
Get the full value from Datadog: correlated metrics/logs/traces, SLOs and burn-rate alerts, dashboards that answer questions, and managed operation — with cost governance and PII protection as hard rules and destructive changes human-gated.
datadog-observability.md
strategy · opsOperations & Value-Driver Analysis
Find where enterprise value is created and lost: a hypothesis-driven, MECE breakdown of the operating model into value drivers and cost-to-serve, converging on the two or three moves that matter.
mckinsey-operations-strategy.md
diagnostic · execEnterprise Health Score
Sync every dimension — financial, spend (software/people/office/legal/admin/product/marketing), people (attrition, satisfaction), market (acceptance, share), product (lifecycle, iteration, repeat-customer) — into one transparent, weighted health score.
deloitte-enterprise-health-score.md
finance · reviewP&L & EBITDA Review
Read a P&L and build a defensible EBITDA bridge: reconcile first, normalise one-offs honestly, keep GAAP separate from adjusted, and flag what a real audit would question. Unaudited — routes to a CPA.
pwc-pnl-ebitda-review.md
risk · ERMMulti-Lens Enterprise Risk
See risk from every angle — strategic, financial, operational, market, regulatory, technology, people, product — scored by likelihood and impact, mapped to owners and mitigations, with interdependencies named.
kpmg-enterprise-risk-analysis.md
finance · forecastRevenue Forecast & FP&A
Build a driver-based revenue forecast a board will trust: grounded in unit economics, tested with base/upside/downside scenarios and sensitivities, honest about assumptions. A range, not false precision.
ey-revenue-forecast-fpna.md
credit · financeFinancial Health & Credit Risk
Judge financial resilience through the cycle — leverage, coverage, liquidity, business risk — into a transparent internal health grade. An internal analytical opinion, never an actual credit rating.
moodys-financial-health-rating.md
market · strategyMarket Position & Share
Where do you actually stand: defined market, triangulated sizing, share and its trajectory, competitive position, and market acceptance — sourced and labelled, not an inflated TAM.
sp-market-position-analysis.md
spend · financeEnterprise Spend Analysis
Full visibility into where the money goes across every cost bucket, then the savings: duplicate tools, unused licenses, auto-renewals, maverick spend — a prioritised, owned savings plan that cuts waste, not growth.
coupa-enterprise-spend-analysis.mdAI Displacement Risk Analysis
Judge how exposed a role, product, or business model is to AI — task-level exposure, the defensible core, commoditisation not just replacement, a realistic horizon — without hype in either direction.
ai-displacement-risk-analysis.mdProduct Logic Adversarial Review
Argue against your own product bet before you commit: steelman the opposing case, red-team the plan, audit the data the claim rests on, run a pre-mortem — so weak logic surfaces in a review room, not the market.
product-logic-adversarial-review.md
org health · execOrganizational Health (OHI & 7S)
Diagnose the org, not the financials: alignment, execution, and renewal — the health that predicts whether performance lasts — read through the OHI and 7S lens, from real organizational input, not a top-down guess.
mckinsey-ohi-7s.md
customer · orgCustomer & Founder’s-Mentality Health
Read health from both ends: customer loyalty (NPS and the reasons behind it) and front-line vitality (insurgency, front-line obsession, owner mindset) — catching “big-company disease” before the numbers do.
bain-nps-founders-mentality.md
strategy · costCapabilities Strategy & Fit for Growth
Test whether spend matches the capabilities the strategy actually needs, then reallocate from the non-differentiating to the vital few — prune to the core, fund what wins. Reallocation, not blunt cost-cutting.
pwc-fit-for-growth.md
ops · techTech & Operations Health (Process Mining)
Map the operation as executed, not as drawn: find the bottlenecks, rework loops, and cash leaks hiding in ERP, supply-chain, and cross-border flows — a fact-based read of where the operation is stuck and what it costs.
deloitte-tech-ops-process-mining.md
change · resilienceTransformation & Resilience Health
Judge readiness to absorb shock — geopolitical, technology, regulatory, market — and the capacity to actually execute the change it demands. Most transformations die on execution; this finds the gaps first.
ey-transformation-resilience.md
controls · complianceRisk & Compliance Controls Health
Check whether the defenses actually hold: control maturity across compliance, cyber, financial, and operational domains through the three-lines-of-defense model — the gap between the policy on paper and the control in practice.
kpmg-compliance-controls-health.md
design · maturityDesign Maturity Assessment
Place a design practice on a five-level ladder — from design-as-decoration up to design-as-business-strategy — and name what caps it. Are your designers skinning finished decisions, or in the room where they’re made?
invision-design-maturity.md
UX · maturityUX Maturity Assessment
Audit how mature a UX practice really is: the research process (real and acted on?), the design system (maintained and governed?), and quality control — placed on a staged UX-maturity scale with the ceiling named.
nng-ux-maturity.md
agency · opsDigital Agency Operations Health
Find why a busy agency isn’t profitable: read the time-tracking data to catch scope creep (endless unpaid revisions), rank the money-losing clients, and fix the pricing and scope structure underneath.
promethean-agency-operations.md
agency · leverageAgency Operational Leverage Health
Check whether the studio’s machine makes money: billable utilization against the healthy ~60–70% range, the non-billable overhead ratio, realized rate, and margin per biller — sustainable leverage, not burnout.
ami-agency-leverage.md
agency · benchmarkDigital Studio Peer Benchmarking
Benchmark a studio against genuine peers on the numbers that matter — compensation, pricing and rates, and margins — to see honestly whether it’s healthy or quietly falling behind the market.
bureau-digital-benchmarking.md
product · PMProduct Conflict Analysis & PRD
Review the history — templates, past PRDs, R&D records — compare a new requirement against the existing architecture to surface logic conflicts, API breaking changes, and schema risk, then write a rigorous edge-case PRD and Jira breakdown.
pm-product-conflict-prd.md
data · growthBackend Data Growth & GEO/SEO
Read backend analytics (funnel, drop-off, retention), find unconsidered functional gaps, then strengthen both traditional SEO and 2026 generative-engine optimization (GEO) — every number from your own data.
backend-data-geo-seo.md
content · marketingBlog Copy & AI-Tone Humanizer
Write and optimize blog content on current SEO/GEO structure, then strip the machine tone — over-narration, empty filler, AI cadence — for a natural, authoritative human brand voice, without fabricating claims.
blog-copy-humanizer.md
developer · engineeringGitHub OSS Discovery & License Audit
Scan trending and relevant repos, match the team’s real needs to existing OSS to avoid reinventing the wheel — with a mandatory license (MIT / Apache-2.0 vs copyleft GPLv3) and maintenance / security check.
github-oss-discovery-audit.md
strategy · productCompetitive Analysis & Market Strategy
A multi-dimensional competitor matrix — UI/UX, DAU/MAU, download and revenue estimates, business model — an objective gap analysis, and a 6–18 month strategy read. Figures labelled as public / inferred estimates, never a rival’s actuals.
competitive-analysis-market-strategy.md
growth · expansionGlobal Expansion & GTM Strategy
Target market, regulatory limits, SWOT, TAM/SAM/SOM, ARPU, plus a GDPR/CCPA and cross-border data check and a landing playbook — estimates with stated assumptions; legal routed to local counsel.
global-gtm-strategy.md
ops · financeR&D Resource & Cost Accounting
Two modes (5–10 team / 11–50 scale-up): headcount and ramp-up cost, engineering-hour scheduling, tech-debt ratio, training, and Cloud/DevOps FinOps (API, GPU, SaaS, build-vs-buy). Models, not audited accounting.
rnd-resource-cost-accounting.md
CRM · wealthHigh-Net-Worth Client Relationship
A private-banking client-tiering and fiduciary lens for a high-stickiness experience and a consented Data Gap Strategy — progressive behavioral tagging that respects privacy. Not affiliated with UBS; not financial advice.
hnw-client-relationship.md
data · productAnalytics Event Taxonomy
From a PRD’s goals, design an event-tracking spec (name, trigger, params) and the funnel + retention logic, with a consistent naming convention, no PII in params, and consent-aware collection.
analytics-event-taxonomy.md
UX · productUser Journey & Friction Mapping
Draw the journey map, annotate the emotion curve and friction at each stage, and give conversion-lifting breakthroughs — grounded in research where available, labelled as inference where not.
user-journey-friction-mapping.md
product · PMAgile Epic & BDD Tickets
Decompose a PRD into Epic → Story → Sub-tasks, write Given-When-Then acceptance criteria, and estimate story points — testable, owned, and team-calibrated, not imposed hours.
agile-bdd-ticket-spec.md
design · trustEthical Dark-Pattern & Trust Audit
Audit a flow for misleading visuals, hidden terms, and trust-damaging dark patterns; give high-transparency fixes aligned to a private-banking service standard and GDPR / FTC — legal determinations routed to counsel.
ethical-dark-pattern-audit.md
design · front-endAccessibility (WCAG 2.1 AA) & i18n Guard
Check contrast, screen-reader labels, and full keyboard operation; review RTL and long-word multi-language overflow — citing the specific WCAG success criteria. Not a substitute for a formal audit or real AT-user testing.
accessibility-i18n-guard.md
strategy · pricingGame Theory & Counter-Strategy
Simulate competitor retaliation — price war, copying, PR — within 1–3 months of a launch or pricing change, and pre-embed a moat and defense. Scenarios, not predictions; no price coordination.
game-theory-counter-strategy.md
comms · founderCrisis PR & Sentiment War Room
Pre-rehearse negative sentiment and PR crises for a sensitive change or incident, and draft a response statement + support FAQ balancing compliance, sincerity, and remediation — a draft for legal review, not a cleared statement.
crisis-pr-sentiment-war-room.md
strategy · execConsultant-Grade Strategy Blueprint
MECE + 7S to produce an enterprise strategy, org-change plan, and a decision blueprint. Not affiliated with McKinsey; the frameworks are used as a reference lens; every figure labelled estimate or measured.
mckinsey-strategy-blueprint.md
design · front-endDesign Tokens & Component States
Decompose a design into design tokens and fill in every component state — Hover, Disabled, Focus, Loading — with Tailwind, verified against the project config; state never conveyed by colour alone (WCAG 1.4.1).
design-tokens-component-states.md
growth · experimentationAutonomous A/B Testing & Personalization
Analyze real-time behavior, switch UI/CTA variants, track statistical significance, and roll out the winner — pre-registered and significance-gated, with a human sign-off on irreversible or high-risk changes.
autonomous-ab-testing-personalization.md
HR · hiringEmployer Branding & Talent Engineering
Track competitor product-team talent flow from public signals, then engineer the funnel: attractive, honest job descriptions and real System-Design / scenario interviews that an AI question-bank can’t game. Public signals only; fair, job-related screening.
employer-branding-talent-engineering.md
HR · people opsOrg Health & Retention Guard
Benchmark comp against the market and watch consented, team-level health signals — pulse surveys, a burnout index — to catch attrition risk early and act humanely. Aggregate and consented, never covert individual surveillance.
org-health-retention-guard.md
developer · auditLong-Context Legacy Codebase Audit
Feed a legacy project — 100K–300K tokens of source, architecture, API specs, migrations — into a local long-context model to surface zombie code, breaking-upgrade risk, and design debt, then propose low-blast-radius refactor PRs with tests. Local, so code never leaves the machine; nothing auto-applies.
legacy-codebase-audit-long-context.md
HR · financeCross-Border Workforce Cost
Cost a team across two scales (5–10 / 11–50) and across geographies — salary, benefits, hardware, SaaS, recruiting, ramp-up — then model regional / remote pay premiums and the ROI of a hire before you make it. Estimates from public data; comp routed to finance and HR.
cross-border-workforce-cost.md
HR · people opsCultural Friction & Retention Guard
Read org health on the dimensions employees rate (balance, trust, growth, pay), surface the cross-team friction (Dev↔PM, PM↔Design) that process and KPI conflicts create, and turn early consented signals into humane retention action. Aggregate and consented, never covert surveillance.
cultural-friction-retention-guard.md
data · engineeringPython Data Science
Turn a messy CSV, API dump, or permitted scrape into a reproducible Python pipeline — clean, join with match rates reported, automate the weekly pull. Raw stays raw; every transform is code, so the number in the deck re-runs. Personal or copyrighted data routes to legal first.
python-data-science.mdStatistical Modeling & Multivariate Statistics
Pick the right model — regression, PCA/clustering, hypothesis tests — check its assumptions, and report effect size with a confidence interval instead of a bare p-value. “Not significant” is a real finding; correlation is labelled correlation; causal claims need a design.
statistical-modeling.md
ML · AIMachine Learning & AI for Business
Decide whether ML or generative AI actually beats a transparent baseline — then frame it, evaluate on a decision-tied metric sliced by segment, and keep a human on the irreversible call. Often the answer is “a simple rule wins,” and the skill says so.
ml-for-business.mdNLP & Sentiment Analysis
Turn reviews, social posts, and tickets into themes, aspect-level sentiment, and early-warning signals — every finding anchored to real quotes, accuracy checked against a labelled sample. Quotes over scores; aggregate and consented, never individual profiling.
nlp-sentiment-analysis.mdMarketing Analytics Science
The quantitative core of growth — CLV, multi-touch attribution, churn prediction, and value-based dynamic pricing — modelled with stated assumptions and backtested against realised cohorts. No last-click gospel, no surveillance pricing; auto-spend and price changes stay human.
marketing-analytics-science.mdBehavioral Economics & Consumer Insight
Decode how consumers really decide — defaults, framing, loss aversion, social proof — as testable hypotheses, then validate the effect with data. Applied to help people choose well, never to manipulate: manufactured urgency and hidden costs are refused.
behavioral-economics-consumer.mdBrand Positioning & Strategy
Build a defensible, provable position — for someone, against something — and the brand equity that earns a price premium, with an architecture that holds as you extend. Grounded in win/loss and competitor evidence, not adjectives; superlatives route to legal.
brand-positioning-strategy.mdMarket Research & Intelligence
Design research that yields decisions — unbiased surveys and sound experiments, plus interviews and observation for depth — then triangulate qual and quant into one trustworthy read. Bias control before collection; every sample and its limits named; consented, never covert.
market-research-intelligence.mdCommercial & Technology Contracts
Draft, review, and negotiate MSAs, SaaS terms, licensing, DPAs, SLAs, and NDAs — spotting the risk-shifting clauses (indemnity, liability caps, IP ownership, auto-renewal, data rights) and building a fallback ladder. Not legal advice; anything signed goes to counsel in the governing jurisdiction.
commercial-tech-contracts.mdIP Strategy & Licensing
Decide what to protect and how — patent vs trade secret vs trademark vs copyright — map a portfolio to the roadmap, and structure technology licensing and cross-border deals. Frames the strategy; patentability, FTO, and filings belong to qualified IP counsel.
ip-strategy-licensing.mdSecured Transactions & Creditors’ Rights
Structure and perfect security interests under UCC Article 9, and navigate insolvency mechanics — liquidation vs reorganization, the automatic stay, priority waterfalls. Recoveries labelled estimates; every filing and priority dispute routed to insolvency counsel.
secured-transactions-bankruptcy.mdAntitrust & Competition Law
Surface competition-law risk before it becomes an enforcement action — per se hazards (price-fixing, market allocation, bid-rigging), merger-review exposure, and abuse-of-dominance concerns. Per se conduct is refused, never structured around; the clearance is counsel’s.
antitrust-competition-law.mdCorporate Compliance & ESG Program
Stand up a risk-based compliance program that actually runs — policies, controls, training, monitoring, whistleblower channels — plus ESG governance with substantiated disclosure. Greenwashing and unsupported claims are flagged; the legal compliance call stays with counsel.
corporate-compliance-esg.mdCorporate Governance & M&A Defense
Navigate board fiduciary duties and the standards courts apply, shareholder activism, and hostile-takeover mechanics and defenses. Strategy framed within duties — not entrenchment; the defensive measures and transaction steps are executed by corporate counsel.
corporate-governance-manda.mdDevOps & CI/CD
Build delivery pipelines that ship safely — CI gated on tests, Docker images pinned by digest, right-sized Kubernetes, canary/blue-green rollout with one-action rollback and secrets hygiene. K8s is justified, not defaulted; the irreversible prod step stays human-gated.
devops-cicd.mdFormal Methods & Quality Assurance
Raise quality with the rigorous end of the toolbox — static analysis, property-based and contract testing, and lightweight formal specification where correctness really matters. Rigor follows risk; “verified” always names its model and assumptions, never “cannot fail.”
formal-methods-qa.mdRequirements Engineering & System Scoping
Turn a fuzzy business ask into precise, testable requirements and a bounded scope — with explicit non-goals, assumptions, and acceptance criteria. If you can’t write the acceptance check, it’s still an idea; the “out of scope” list is real and specific.
requirements-engineering.mdDistributed Systems Architecture
Design cloud-native systems that hold up — making the consistency/partition/failure trade-offs explicit (CAP/PACELC), choosing serverless vs containers vs cluster by real load, idempotent by default, infra as code. Distribution is questioned before it’s adopted.
distributed-systems-architecture.mdAI for Code & Code Intelligence
Use LLMs and coding agents where they genuinely help — refactoring, debugging, test generation, code comprehension — inside a discipline that keeps a human accountable: every diff reviewed, tests as the gate, the merge human-owned. The model produces; the engineer governs.
ai-for-code.md
AI · agentsLocal Tool-Use Router
Give a local open-weight model real agent execution — a ReAct loop plus an API interceptor that lets it trigger Python, database queries, and webhooks, with schema validation, an allowlist, and a human gate on the irreversible. The model proposes the call; the harness disposes.
local-tool-use-router.md
AI · servingDynamic LoRA Router
Serve one base model as many specialists — an intent classifier hot-swaps task-specific LoRA adapters (PRD, code refactor, HR) at inference, with cached adapters, a confidence threshold, and a base-model fallback. Specialized depth per task, measured switch latency — not a claim of frontier general intelligence.
dynamic-lora-router.mdNo skills match — try a tool name, a task, or a domain.
Start · Agent Library
The other artifact: sixty-two master agents.
The skills above are methods — how to do a piece of work. A second body of files does the opposite: each one describes a mind in enough structural detail that a model can argue from inside it rather than about it. Same artifact class as everything else here — plain Markdown, no runtime, no dependencies, no account. Written across three traditions so the format had to survive translation, not just repetition.
Why this sits next to a design system. A design system and an agent specification are the same discipline pointed at different material: decide the structure once, make every instance conform, and let the conformance be checkable rather than asserted. The counts on this page and on the library page are generated from the files themselves, not typed in. Read them together and the claim is about method, not volume. Browse the whole set — sources, structure and per-agent downloads — at the Agent Library →
Start · AI-Ready Export
Compile your Design.md pack.
One file that makes any AI tool fluent in this system: the seven-step agent protocol, the blockable hard rules, the bundled-by-contract pairs, the component index for the domains you pick, the matching skill methods, the dual-theme token set, and setup for your tool. Compiled client-side from the same live contracts agents fetch — 190 components across 17 domains and 119 skill methods. No model involved, nothing invented.
- Agent protocol · 7 steps
- Hard rules · blockable
- Bundled-by-contract pairs
- 190 / 17 domains
- Skills · 119 / 6 cat.
- Dual-theme tokens
- Motion contract
Pick a category or take them all — 119 methods across 6 categories. Each ships in the pack with its download URL, grouped by category.
Pick a target and domains, then compile — the pack renders here.
Honest scope. The pack is assembled deterministically from components.json and tokens.json — the same files an MCP server would serve; if this page is opened offline the compiler falls back to reading the catalogue's own navigation and says so inside the pack. The "AI-ready Design.md package" idea has been popularised by tools like Alpy Studio — this implementation is original, and generated from a live, versioned system rather than a form.
Core
Data Table
The workhorse nobody designs and everybody ships badly. A table earns its complexity only when the data is genuinely tabular — rows you compare, columns you sort. Anything else is a list wearing a grid.
Homogeneous records the user needs to scan, sort, and compare across fields — transactions, orders, members. Right-align numbers, keep the header visible while the body scrolls, and make the sort state unmistakable.
Never for a single record's details — that is a description list, not a table. Never on a phone without a plan: a 9-column table on a 375px screen is a horizontal-scroll trap. Never encode the sorted column by colour alone.
Real <table> semantics; sortable headers are <button>s inside
<th> with aria-sort that updates, and the direction is shown with a
glyph, not just a hue. Row selection has a header “select all” whose indeterminate state is
real. Numbers use tabular figures so columns line up.
WCAG 2.2 · 1.3.1 info and relationships, 1.4.1 use of colour, 1.4.10 reflow; WAI-ARIA sortable table pattern; HIG Tables; Material 2 data tables — Material 3 has never documented the component, which is itself the reason this entry specifies one.
Sort state lives in aria-sort and shows a ↑/↓ glyph
— never colour alone.
Core
Command Palette
The power-user shortcut that has quietly become a mainstream expectation: press ⌘K, type, jump anywhere. It rewards the keyboard without punishing the mouse.
Apps with more destinations and actions than a nav bar can hold. It is an accelerator layered over the UI, never a replacement for it — everything reachable here is also reachable by pointing.
Never as the only path to a feature — a command a user cannot discover by looking is a feature most users do not have. Never on a small, shallow app where it is ceremony. Never hide the shortcut and hope people guess it.
The input is a combobox owning a listbox; aria-activedescendant
tracks the highlighted result so a screen reader hears it without moving DOM focus. Focus is trapped while
open and restored on close. Esc closes; the match count is announced.
WAI-ARIA Combobox pattern (list-with-inline-autocomplete); WCAG 2.2 · 2.1.2 no keyboard trap (a deliberate, escapable one), 4.1.3 status messages; HIG Keyboard shortcuts.
No matches.
Everything here is also reachable by pointing — the palette is an accelerator, not the only door.
Core
Tooltip
A tooltip explains; it never contains. The moment something important only exists on hover, it has vanished for every touch user and every keyboard that isn't pointing at it.
A short, supplementary label for an icon-only control, or a plain-language gloss on a term. It clarifies an element that already has an accessible name — it does not supply the only one.
Never for essential instructions, interactive content, or anything a touch user must read — there is no hover on a phone. Never as the only label for a control. Never on a delay so long the user has moved on, or so short it flickers.
Shows on hover and keyboard focus; dismissible with Esc while the pointer stays (WCAG 1.4.13);
linked by aria-describedby so it is announced. It never traps the pointer and never obscures
the element it describes.
WCAG 2.2 · 1.4.13 content on hover or focus, 4.1.2 name/role/value; WAI-ARIA Tooltip pattern; Material 3 Tooltips (plain).
Each button already has an aria-label; the tooltip adds detail, it isn't
the only name.
Core
Copy to Clipboard
The smallest interaction with the highest trust stakes: it either did the thing or it didn't, and the user cannot see the clipboard. So the one rule is — never fail silently.
Any value the user needs elsewhere — a code, an API key, a share link, a wallet address. Put the control next to the value, confirm the copy visibly, and revert after a moment.
Never as the only way to get the value — the text must still be selectable. Never claim success you didn't verify: the Clipboard API can reject (permissions, insecure context), and a green tick over a failed copy is worse than an honest error.
Success and failure are announced via role="status", not shown by colour alone. The label
changes text (“Copied”), not just an icon. Focus stays on the button so a keyboard user hears
the result. It awaits the promise and reports what actually happened.
WCAG 2.2 · 4.1.3 status messages, 1.4.1 use of colour; Async Clipboard API (secure-context, permission-gated); HIG feedback conventions.
sk_live_5f3a9c2e8b41
The value stays selectable, and the button tells you what actually happened — not just a hopeful tick.
Core
Rating Input
Stars are a radio group in a costume. Treat them as decoration and you lock out every keyboard and screen-reader user from an action the whole product is asking them to take.
Collecting a discrete score — a review, a satisfaction rating. Show the current value in words as well as fill, and let the user change or clear it before submitting.
Never for display-only averages — that is static output, not an input, and it must not be tabbable or look clickable. Never force a rating to proceed. Never rely on hover to reveal the value on touch, where hover doesn't exist.
A radiogroup of real radios (visually stars); arrow keys move between values, and each option
has a text label (“3 stars”). The selected value is announced. Fill is never the only signal
—
the chosen number is stated.
WAI-ARIA Radio Group pattern; WCAG 2.2 · 1.4.1 use of colour, 2.5.3 label in name; HIG Ratings and reviews.
No rating yet
Core
Tag Input
Turning free text into removable tokens — skills, recipients, filters. The failure mode is a box that eats your entries into a black hole: added, but no way to see or remove them one by one.
Collecting a set of short, discrete values where each should be individually visible and removable. Enter or comma commits a token; Backspace on an empty field removes the last.
Never for a single value — that is a plain input. Never for a fixed, known list — that is a multi-select. Never make a committed tag impossible to remove, or removable only by clearing everything.
Each tag is focusable with its own remove control that has a discernible name (“Remove design”, not just “×”). Adding and removing are announced via a live region. The text field keeps focus so entry flows; duplicates are rejected quietly, not silently swallowed.
WCAG 2.2 · 4.1.3 status messages, 2.4.4 link/label purpose, 2.1.1 keyboard; WAI-ARIA grouping and live-region practice.
Enter or comma adds · Backspace on an empty field removes the last.
Core
Relative Time
“2 hours ago” is friendlier than a timestamp and lies more easily. It is only honest if the exact time is one hover away and the reader's own timezone is respected.
Recent, human-scale events in feeds, activity, and chat — where “just now” and “5 min ago” read better than a full date. Always back it with the absolute time.
Never for anything the user must act on by a deadline — “in 3 days” hides the actual date a bill is due. Never for records or receipts, where the precise, localized timestamp is the point. Never render in the server's timezone and call it the user's.
A <time> element carries the machine-readable datetime; the exact,
timezone-correct value is available on hover and in title, so it is never lost. Text updates
as time passes without stealing focus or spamming a live region.
HTML <time datetime>; Intl.RelativeTimeFormat for locale; WCAG 2.2 ·
1.3.1 info and relationships; GDPR-adjacent honesty — a due date is not a vibe.
Relative on the surface, exact underneath — the real timestamp is in
datetime and on hover, never thrown away.
Spatial & Motion
Motion Role Tokens
Most systems size their motion: small things move fast, big things move slowly. That is a measurement, not a meaning. These tokens are typed by what the movement is for, so a component picks a role and never picks a millisecond.
As the layer above a duration scale, not a replacement for it. --dur-1/2/3 still answer
“how big is this element”. These answer “what is this movement doing to the user” —
and that is the question that decides whether 380 ms feels crisp or 380 ms feels broken.
Never add a role because a screen felt slightly off; five is already near the ceiling of what a team can hold in their heads, and a sixth role is usually a component that picked the wrong one. Never let a component hard-code a duration “just this once” — that is how a system loses the ability to retune itself in one commit.
Every role collapses to 1 ms under prefers-reduced-motion: reduce, at the token, so no
component can forget. Motion is never the only carrier of a state change: each role has a
non-animated counterpart in text, position or an attribute.
WCAG 2.2 §2.3.3 Animation from Interactions (motion triggered by interaction can be disabled); §2.2.2 Pause, Stop, Hide. Material 3 motion scheme (duration and easing as paired tokens); Apple HIG — Motion (“use motion to explain, not to decorate”).
Pick a role to run it
Ambient is twice Navigation on purpose. A backdrop that arrives in 180 ms reads as “a layer appeared”; the same backdrop over 720 ms reads as “the room went quiet”. Same opacity, opposite meaning — and the only variable is time.
Spatial & Motion
Focus Zoom
Opening an item as a camera move rather than a layer. The item you chose becomes the subject; everything else stays exactly where it was, quieter. Nothing is covered, so nothing has to be remembered.
Any surface where the user placed the items themselves — boards, canvases, galleries, maps, spatial note tools. The user built the arrangement; a modal throws it away and asks them to rebuild it from memory every time they open something.
Never for destructive confirmation, consent, payment or anything that must not be dismissed by accident — those need a real focus trap and an explicit choice, which is exactly what this pattern removes. Never on a list the system ordered rather than the user: there is no spatial memory to preserve, so the zoom is just a slow navigation.
Escape and a second activation both return; the return lands the item back at its original coordinates, not
at a re-flowed position. Attenuated peers are set aria-hidden and removed from the tab order
— visually present is not the same as programmatically present, and handing a screen reader a room the
sighted user has already left is worse than a modal. Cards are real controls: reachable by Tab, operable by
Enter and Space.
WCAG 2.2 §2.4.3 Focus Order; §3.2.3 Consistent Navigation; §2.4.11 Focus Not Obscured (Minimum). Material 3 container transform (the origin persists through the transition); Apple HIG — Navigation, on preserving a sense of place.
Click any card to make it the subject
The peers do not fade to nothing. They fade to a floor, and they hold their coordinates — so returning is recognition rather than re-orientation. A modal is cheaper to build and costs the user their place every single time.
Spatial & Motion
Attenuated Context
The alternative to a scrim. Instead of covering what the user was doing, turn its volume down — and stop short of zero, because the last third of the fade is what they are using to keep their place.
For transient, reversible, non-committal surfaces: a formatting menu, an inspector, a quick-add, a preview. Anything the user will open dozens of times an hour and where re-finding their position each time is the real cost.
Never for consent, payment, deletion or any decision with a legal or destructive consequence. Those need a genuine modal with a focus trap, because “the background is still faintly operable-looking” is the exact ambiguity you must not create when the user is about to be charged. Never attenuate below the floor and then leave the content focusable — invisible-but-tabbable is a trap.
Attenuated content is inert and aria-hidden for as long as it is attenuated: it
is
not readable, so it is not offered. The floor exists to preserve place, never to preserve reading
— do not defend attenuated text on contrast grounds, defend it on the grounds that nobody is being
asked to read it. Escape and an outside click both restore, and restoration returns focus to the control
that opened the panel.
WCAG 2.2 §4.1.2 Name, Role, Value (via the HTML inert attribute); §2.4.11 Focus Not
Obscured (Minimum); §1.4.3 Contrast (Minimum) applies to content that is offered for reading,
which attenuated content explicitly is not. Material 3 scrim guidance; Apple HIG — Modality.
Notes on density
A dense screen is not a crowded screen. Density is a measure of how much of what is on the surface the reader can act on; crowding is a measure of how much of it they must first ignore.
The distinction matters because the fix is opposite in each case. A crowded screen is fixed by removal. A screen that is merely dense is usually made worse by removal, because the thing removed was the thing that made the rest interpretable.
Which is why “simplify it” is not a brief. It names a direction without naming the quantity being reduced.
Drag the floor to zero while the panel is open. The document does not become “more focused” — it becomes a different screen, and closing the panel now costs a re-orientation. The floor is not a styling preference; it is the thing being designed.
Spatial & Motion
Anchored Control
A control that opens from the object it edits, and keeps its handle visible while it is open. The user never has to hold “which block am I changing” in their head, because the answer is drawn on the screen.
Block editors, canvas objects, table cells, layers, timeline clips — anywhere a menu acts on one specific object among several that look alike. The more uniform the objects, the more the anchor is doing.
Not for global commands: a command palette acts on the document, not on an object, and anchoring it to wherever the caret happened to be is a false claim about scope. Not when the anchor would push the menu off a small viewport — below the breakpoint, promote it to a sheet with the object’s name in the title, which is the same guarantee by other means.
Implements the ARIA menu-button pattern: the handle carries aria-expanded, focus moves to the
first item on open, Escape closes and returns focus to the handle. The handle stays rendered and visibly
active for the whole open state — the connection is a persistent object, not an animation that
already finished. The menu never covers the object it edits.
WCAG 2.2 §1.4.13 Content on Hover or Focus (dismissable, hoverable, persistent); §2.4.11 Focus Not Obscured (Minimum); §2.4.3 Focus Order. ARIA Authoring Practices — Menu Button pattern; Material 3 menu anchoring.
A brief history of Scandinavian design.
Born in the Nordic countries, the movement held that beautiful, functional objects should be available to everyone rather than to a wealthy few.
Its clean lines and natural materials continue to define modern interiors around the world.
Switch to cursor anchoring and open two menus from different places on the same block. Nothing broke — and that is the point. The relationship is still true, it is simply no longer drawn, so the user now has to carry it.
Spatial & Motion
Draw to Create
Creation as a direct gesture: drag out the space the thing will occupy and it exists, already focused, already the size you asked for. The neighbours yield while you are still dragging, so the outcome is visible while the decision is still reversible.
Canvases, boards, timelines, calendars, floor plans — anywhere the object’s size and position are part of what the user is deciding. A dialog asking for width and height after the fact is asking the user to describe something they could simply have drawn.
Never as the only way to create. A drag is a compound gesture: it excludes switch access, most screen-reader interaction, users with tremor, and anyone on a trackpad in a moving vehicle. Never for objects whose size is meaningless — if the system will normalise it anyway, the drag was theatre.
A single-pointer, non-dragging alternative is mandatory and is shipped alongside, not hidden in a menu: the button creates at a sensible default size in a free position. Live dimensions are announced in text, not only drawn. Below a minimum size the gesture is treated as a click and creates nothing, so a stray drag never litters the canvas.
WCAG 2.2 §2.5.7 Dragging Movements (AA, new in 2.2 — any dragging action needs a single-pointer alternative); §2.5.1 Pointer Gestures; §2.5.5 Target Size (Enhanced, AAA) with §2.5.8 Target Size (Minimum, AA) as the floor. Apple HIG — Direct manipulation; Material 3 drag-and-drop accessibility guidance.
Drag to draw a note — the neighbour moves while you draw, not after
The button is not a fallback bolted on for compliance. It is placed next to the canvas at the same visual weight, because a “secondary” accessible path is a path the team will eventually forget to maintain.
Spatial & Motion
Elevation on Commit
Shadow as a state signal rather than a decoration. An object in the user’s hand is lifted; the moment it is placed it settles back down. Elevation stops being a style token and starts answering a question: is this thing mine right now, or is it the system’s?
Drag-and-drop, reordering, resizing, any transfer of custody between the user and the layout engine. The lift is the promise that the move is not yet committed; the settle is the receipt that it is.
Never as the only indicator of the drag state — shadow is a hue-and-luminance cue and disappears at high contrast, on e-ink, and for many low-vision users. Never apply a constant elevation to every card and call it hierarchy; if everything is lifted, nothing is held.
Elevation always ships with a non-visual partner: the destination slot is drawn, the state is exposed by a
live-region
announcement — not aria-grabbed, which was deprecated in ARIA 1.1, removed in 1.2, and is
implemented by nothing current, and a keyboard reorder path exists. The lift is
instantaneous (transition removed while the pointer is down, so the object never lags the finger); only the
settle is animated, on the Settle role.
WCAG 2.2 §1.4.1 Use of Color (elevation must not be the sole carrier); §2.5.7 Dragging Movements; §1.4.11 Non-text Contrast for the destination slot. Material 3 elevation levels; Apple HIG — Materials and the meaning of depth.
The shadow is the difference between holding and having placed
With constant elevation the card still moves, still lands, still works. What is missing is the moment of custody — you can no longer feel the difference between dragging and having dropped, so you check the screen instead of trusting your hand.
Spatial & Motion
Shortcut-Teaching Menu
A menu that prints its own keyboard path on every row, at rest, and notices when you have taken the slow route three times. The pointer is never punished — it is simply not the only thing the interface is willing to talk about.
Any surface a user will touch dozens of times a day: block menus, command palettes, editor toolbars, triage queues. The value is compounding, so it belongs where frequency is high and the population is long-lived.
Never in a one-off flow — checkout, onboarding, a settings page visited twice a year. Teaching a shortcut for something nobody repeats is noise dressed as generosity. And never advertise a key the build does not actually honour: one dead shortcut teaches the user to stop reading the column.
Shortcuts are shown at rest, not on hover, so they are legible to someone who never hovers. The nudge appears inline, once, and never blocks, never re-appears in the session, and never gates the pointer path. Single-character shortcuts are avoided or made remappable, because they collide with speech input and typing.
WCAG 2.2 §2.1.4 Character Key Shortcuts (remappable, or active only on focus); §3.3.5 Help; §2.1.1 Keyboard. ARIA Authoring Practices — Menu and Menubar keyboard interaction.
The nudge is not a tooltip and not a modal. It is a line of text that appears once, inside the surface the user already opened, and never asks to be dismissed. If the user ignores it forever, nothing degrades — which is the only version of this pattern that is not a tax.
Spatial & Motion
Stack Gather
Collapsing a selection into one object without pretending the members stopped existing. The pile is legible as a pile — which, for a set of same-shaped cards, takes a deliberate rotation of between 0.8° and 3°, and nothing else.
Grouping on a canvas, collapsing a multi-select, tidying a board, archiving in place. Any time the user wants fewer things on screen but has not decided to remove any of them.
Never as a substitute for a real container with a name — a pile the user cannot label is a pile they will not find again. Never let the gather be lossy or reorder the members silently: fanning back out must return the original arrangement, or the gesture is a one-way door disguised as a tidy-up.
The rotation jitter is seeded, not random — two people opening the same board must see the same stack, because decorative randomness is still state. The magnitude carries a floor as well as a ceiling: an unbounded ±3° range eventually deals one card 0.01°, and that card disappears into the pile it was supposed to be counted in. The count is rendered as text, never inferred from the visual depth. Under reduced motion the rotation is dropped entirely and the stack stays readable through offset alone, so the pattern degrades rather than disappearing.
WCAG 2.2 §1.3.1 Info and Relationships (the group is a real relationship, exposed as one); §1.4.1 Use of Color; §2.3.3 Animation from Interactions. Apple HIG — Grouping; Material 3 selection and container patterns.
Five cards, one pile — and five is written down, not counted from the edges
Set the rotation to zero and the pile becomes a single rectangle: five cards that render as one. The jitter is not decoration bolted on afterwards — it is the only thing carrying the cardinality, which is why it is specified with a floor rather than improvised with a random range.
Mobile
Safe Area & Insets
The screen is not the rectangle you were given. A notch, a Dynamic Island, a home indicator and a rounded corner all take bites out of it, and every one of them is a place where a control is visible but cannot be pressed.
Any full-bleed surface: edge-to-edge media, sticky headers, bottom bars, sheets, and anything drawn behind translucent chrome. Background art extends into the inset; anything interactive or readable stops at it.
Never hard-code the numbers. A device you have not seen yet will have different ones, and the same device reports different insets in landscape, in split view, and while a call is in progress. Read them, do not type them.
Interactive targets clear the home-indicator band entirely so a tap is never eaten by the system gesture. Insets are re-read on rotation and on multitasking changes, not measured once at launch. Text that reflows into an inset is a 1.4.10 failure, not a cosmetic one.
HIG Layout (safe areas, Dynamic Island, home indicator); CSS Environment Variables Level 1 · env(safe-area-inset-*); Material 3 window insets; WCAG 2.2 · 1.4.10 reflow.
Insets respected — Compose clears the home indicator by 22px.
Mobile
Keyboard Avoidance
The software keyboard takes half the screen and gives no warning. The contract is that the field you are typing in, the thing you are typing about, and the button that submits it are all still visible when it arrives.
Every screen with a text field: composers, checkout, search, comment threads, forms. The keyboard is not an edge case on mobile — it is the second half of every input interaction.
Do not solve it by shrinking the page into an unreadable strip, and do not animate the lift on a timer. Follow the real inset event; a guessed 260px is wrong the moment a hardware keyboard, a floating keyboard, or a language with a candidate bar appears.
WCAG 2.2 · 2.4.11: the focused field is never fully hidden by the keyboard or by the sticky bar riding above it. Scroll position is adjusted, not the layout torn apart. Dismissal restores the previous scroll offset so the reader does not lose their place.
HIG Onscreen keyboards; Android WindowInsetsCompat · IME insets and adjustResize; VisualViewport API; WCAG 2.2 · 2.4.11 focus not obscured (minimum).
Keyboard down — IME inset 0px.
Mobile
Edge-Swipe Back
The system owns the left edge. Everything you put there — a carousel, a slider, a swipeable row — is competing with the gesture people use to leave, and the gesture wins.
On every pushed screen. The gesture should be interactive and reversible: the previous screen follows the finger, and letting go below the threshold puts the current screen back without navigating.
Never place a horizontally draggable control inside the edge zone, and never disable the gesture to protect unsaved work — that is what a save prompt is for. Disabling back is how an app earns a force-quit.
WCAG 2.2 · 2.5.7: a visible Back control does everything the gesture does, because the gesture excludes switch access, keyboards, and anyone who cannot drag. The destination is announced on arrival, and a cancelled swipe announces nothing.
HIG Gestures (interactive back gesture, system edge protection); Android predictive back; WCAG 2.2 · 2.5.7 dragging movements, 2.1.1 keyboard.
Detail screen. Edge zone is 28px — nothing draggable lives there.
Mobile
Thumb Reach
A phone held in one hand has a comfortable arc, a stretch, and a corner most people re-grip to reach. Where you put the primary action decides whether the interface is used walking, or only sitting down.
Whenever a screen has one obvious next step. Put it in the bottom band, full width or near it, and leave the top for identity, title, and things that are read rather than pressed.
Not for destructive actions, which belong away from the resting thumb and behind a confirm or an undo. And not as an excuse to stack four bottom bars: the reachable band is scarce, so it holds one decision.
WCAG 2.2 · 2.5.8: 24×24 CSS px minimum, and this system holds 44×44 for anything used in motion. Reach is a comfort argument, never a correctness one — every bottom action also exists somewhere a keyboard, a switch, or a screen reader can find it.
HIG Layout (bottom-anchored controls, Reachability); Material 3 bottom app bar and FAB placement; WCAG 2.2 · 2.5.8 target size (minimum).
Primary action sits in the easy zone — 44px tall, reachable without re-gripping.
Mobile
Dynamic Type
Someone has already chosen their text size, system-wide, before they ever opened your app. Honouring it is not an accessibility feature — ignoring it is a bug that hides a third of your users' content.
Everywhere text appears. Scale from the system setting, size containers in relative units, and let rows become stacks when the text no longer fits beside the thing it labels.
Never cap the scale to protect a layout, and never truncate a label to one line at the largest sizes. Fixed-height rows, single-line buttons and icon-plus-label pairs that refuse to wrap are where this breaks.
WCAG 2.2 · 1.4.4: readable and operable to 200% without loss of content or function; 1.4.10 reflow at 320 CSS px; 1.4.12 survives user text spacing. Accessibility sizes reflow rows to stacks rather than clipping, and the bold-text setting is honoured alongside the size.
HIG Typography (Dynamic Type, larger accessibility sizes); Material 3 font scaling and non-linear scale; WCAG 2.2 · 1.4.4 resize text, 1.4.10 reflow, 1.4.12 text spacing.
Tuesday, 09:00–12:00
Default size (1.00×) — row layout, nothing truncated.
Mobile
Lifecycle & State Restoration
A mobile app is interrupted constantly and killed silently. The measure of quality is what the user finds when they come back: the same screen, the same scroll position, the same half-written sentence.
Any flow longer than one screen, and every text field with more than a few words in it. Persist on backgrounding, not on a timer, and restore to the exact screen rather than to the root of the app.
Do not restore anything sensitive without re-authentication, and do not restore a modal that was mid-payment as if nothing happened. Restore the place, re-verify the permission.
WCAG 2.2 · 3.3.7: information the user already entered is never asked for twice. 2.2.6 warns before any inactivity timeout that would discard data. Restoration is announced only if the screen changed under them; silent, correct restoration needs no announcement.
UIScene state restoration and app lifecycle (HIG); Android lifecycle, SavedStateHandle and process death; Page Visibility API; WCAG 2.2 · 3.3.7 redundant entry, 2.2.6 timeouts.
Active. The draft exists in memory and on disk.
Mobile
Low Power & Data Saver
Battery saver, data saver and reduced motion are all the same instruction in different words: this person has told the system to spend less on their behalf. An app that ignores it is spending someone else's money.
Anything continuous: autoplay, polling, background sync, live location, decorative animation, prefetch. Degrade the expensive layer and keep the function — the content still arrives, it just stops arriving unasked.
Never degrade correctness. A saver mode that drops a message, skips a security check, or silently stops an upload is not thrift, it is a defect wearing a battery icon.
prefers-reduced-motion collapses movement to opacity; prefers-reduced-data drops poster-weight images and autoplay. Every degradation is visible and reversible in one tap, and the user is told what changed rather than left to notice.
iOS Low Power Mode and HIG Motion (reduce motion); Android battery saver and Data Saver; Media Queries Level 5 · prefers-reduced-motion, prefers-reduced-data; Network Information API saveData.
Full mode — autoplay on, polling every 5s, live dot animating.
Mobile
Orientation & Foldables
The window can change size mid-sentence — a rotation, a fold opening, a second app sliding in beside you. The layout is allowed to change shape; the user's place in it is not.
Design to width classes, not to device names. Compact stacks, medium splits, expanded shows list and detail together — and a fold or a rotation simply moves you between them.
Lock orientation only where the content genuinely has one — a camera viewfinder, a game, a signature pad. Locking a reading or form screen to portrait is a 1.3.4 failure and a hardship for anyone whose device is mounted.
WCAG 2.2 · 1.3.4: content works in both orientations unless one is essential. Scroll position, selection, focus and in-flight input survive the change; a re-layout that restarts a form is data loss with an animation on it.
HIG Layout (multitasking, split view, foldables); Material 3 window size classes and adaptive layouts; Device Posture API; WCAG 2.2 · 1.3.4 orientation, 1.4.10 reflow.
Compact — one pane, detail pushes. Selected: Field notes.
Mobile
Live Activity
A task that is already running, shown where the phone is already being looked at: the lock screen. It earns that place by being finite, by ending, and by never needing the app to be opened.
Bounded, user-initiated, genuinely live: a delivery, a ride, a timer, a match, an upload. There is a start the user asked for, a middle that changes, and an end that arrives on its own.
Never for marketing, re-engagement, or anything open-ended. An activity that has no end state is a permanent advertisement on someone's lock screen, and it will be revoked — by the user, then by the platform.
WCAG 2.2 · 4.1.3: each update is a status message, not a focus steal. The compact and expanded presentations carry the same facts; the expanded one adds detail, never new meaning. It ends in a terminal state and dismisses itself.
HIG Live Activities (Dynamic Island, lock screen) and widgets; Android ongoing notifications and foreground services; WCAG 2.2 · 4.1.3 status messages, 2.2.4 interruptions.
Idle. Nothing is running, so nothing is on the lock screen.
Mobile
Deep Link & Cold Start
A link is a promise that a specific thing is one tap away. Landing on the home screen instead — or on a login wall that forgets where you were going — breaks it, and the user rarely tries twice.
Every shareable object gets a URL that resolves the same way from a cold start, a warm app, a notification, or a browser. Authentication interrupts the journey and then completes it.
Do not drop the destination while authenticating, and do not leave the user on a screen with no way up: a link that arrives cold has no history, so the back stack has to be synthesised rather than left empty.
WCAG 2.2 · 3.2.3 and 2.4.5: the destination reached by link looks and navigates like the same screen reached by browsing, and there is more than one way to get there. An unresolvable link explains what was missing instead of silently landing on home.
Universal Links and App Clips (HIG); Android App Links and synthetic back stack (TaskStackBuilder); WCAG 2.2 · 3.2.3 consistent navigation, 2.4.5 multiple ways.
No link opened yet.
That stretch past the pier is my favorite mile in the city.