@hegemonart/get-design-done 1.18.0 → 1.19.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (63) hide show
  1. package/.claude-plugin/marketplace.json +11 -5
  2. package/.claude-plugin/plugin.json +10 -4
  3. package/CHANGELOG.md +51 -0
  4. package/README.md +7 -0
  5. package/SKILL.md +10 -4
  6. package/agents/README.md +53 -0
  7. package/agents/a11y-mapper.md +10 -0
  8. package/agents/component-benchmark-harvester.md +11 -0
  9. package/agents/component-benchmark-synthesizer.md +11 -0
  10. package/agents/component-taxonomy-mapper.md +10 -0
  11. package/agents/design-advisor.md +10 -0
  12. package/agents/design-assumptions-analyzer.md +10 -0
  13. package/agents/design-auditor.md +15 -0
  14. package/agents/design-authority-watcher.md +10 -0
  15. package/agents/design-component-generator.md +10 -0
  16. package/agents/design-context-builder.md +6 -1
  17. package/agents/design-context-checker-gate.md +10 -0
  18. package/agents/design-context-checker.md +10 -0
  19. package/agents/design-discussant.md +10 -0
  20. package/agents/design-doc-writer.md +12 -0
  21. package/agents/design-executor.md +11 -1
  22. package/agents/design-figma-writer.md +10 -0
  23. package/agents/design-fixer.md +10 -0
  24. package/agents/design-integration-checker-gate.md +10 -0
  25. package/agents/design-integration-checker.md +10 -0
  26. package/agents/design-paper-writer.md +10 -0
  27. package/agents/design-pattern-mapper.md +11 -0
  28. package/agents/design-pencil-writer.md +10 -0
  29. package/agents/design-phase-researcher.md +11 -1
  30. package/agents/design-plan-checker.md +10 -0
  31. package/agents/design-planner.md +10 -0
  32. package/agents/design-reflector.md +10 -0
  33. package/agents/design-research-synthesizer.md +10 -0
  34. package/agents/design-start-writer.md +10 -0
  35. package/agents/design-update-checker.md +10 -0
  36. package/agents/design-verifier-gate.md +10 -0
  37. package/agents/design-verifier.md +11 -0
  38. package/agents/gdd-graphify-sync.md +10 -0
  39. package/agents/gdd-intel-updater.md +10 -0
  40. package/agents/gdd-learnings-extractor.md +10 -0
  41. package/agents/motion-mapper.md +10 -0
  42. package/agents/token-mapper.md +10 -0
  43. package/agents/visual-hierarchy-mapper.md +10 -0
  44. package/hooks/gdd-decision-injector.js +30 -8
  45. package/package.json +16 -3
  46. package/reference/data-visualization.md +333 -0
  47. package/reference/form-patterns.md +245 -0
  48. package/reference/information-architecture.md +255 -0
  49. package/reference/onboarding-progressive-disclosure.md +250 -0
  50. package/reference/platforms.md +346 -0
  51. package/reference/registry.json +409 -360
  52. package/reference/rtl-cjk-cultural.md +353 -0
  53. package/reference/schemas/insight-line.schema.json +37 -0
  54. package/reference/user-research.md +360 -0
  55. package/scripts/lib/design-search.cjs +206 -0
  56. package/scripts/lib/probe-optional.cjs +29 -0
  57. package/scripts/lib/relevance-counter.cjs +121 -0
  58. package/skills/complete-cycle/SKILL.md +40 -2
  59. package/skills/continue/SKILL.md +23 -0
  60. package/skills/pause/SKILL.md +40 -14
  61. package/skills/recall/SKILL.md +74 -0
  62. package/skills/resume/SKILL.md +34 -16
  63. package/skills/timeline/SKILL.md +65 -0
@@ -0,0 +1,333 @@
1
+ # Data Visualization — Chart Selection and Best Practices
2
+
3
+ Source: nextlevelbuilder/ui-ux-pro-max-skill (MIT) — data/charts.csv
4
+
5
+ Charts are not decorations — they are arguments. Every chart type encodes a specific analytical claim, and choosing the wrong encoding forces the reader to decode the wrong claim. This reference provides decision rules for selecting chart types, configuring them accessibly, and avoiding the most common misuses.
6
+
7
+ ---
8
+
9
+ ## 1. Chart-Choice Matrix — Decision Framework
10
+
11
+ Every chart serves one of six analytical purposes: **comparison** (how do values rank against each other?), **composition** (how does a whole break into parts?), **distribution** (how are values spread?), **relationship** (do two or more variables correlate or influence each other?), **trend** (how does a value change over time?), or **geographic** (how does a value vary by location?). Identifying the purpose before choosing a chart eliminates most bad chart decisions.
12
+
13
+ ### Comparison
14
+
15
+ | Chart type | When to use | When to avoid |
16
+ |---|---|---|
17
+ | Bar (vertical) | Comparing discrete categories; up to ~15 categories | When category labels are long — they collide |
18
+ | Bar (horizontal) | Long category labels; ranked lists; > 8 categories | When comparing time series — use line instead |
19
+ | Bullet | Comparing a value against a target range (KPI context) | For more than ~8 metrics on one screen |
20
+ | Slope | Showing how two time points changed relative to each other; showing rank reversal | More than two time points — use a line chart |
21
+
22
+ ### Composition
23
+
24
+ | Chart type | When to use | When to avoid |
25
+ |---|---|---|
26
+ | Pie | Part-of-whole with ≤ 5 slices; slices differ substantially in size | > 5 categories; comparing slice sizes precisely |
27
+ | Donut | Same as pie; center space holds a summary number (total, %) | Any context where the center number distracts from part-whole reading |
28
+ | Stacked Bar | Part-of-whole across multiple categories or time points | When the interior segments (not just the bottom) need to be compared — interior comparison is unreliable |
29
+ | Treemap | Hierarchical part-of-whole; sizes span orders of magnitude | Showing change over time; fewer than ~8 leaf nodes (bar is clearer) |
30
+ | Sunburst | Hierarchical part-of-whole when hierarchy depth matters (2-3 levels) | More than 3 hierarchy levels; when labels must be legible for all segments |
31
+ | Waterfall | How a starting value reaches an ending value through additions and subtractions | Non-sequential cumulative data; when intermediate steps have no story value |
32
+
33
+ ### Distribution
34
+
35
+ | Chart type | When to use | When to avoid |
36
+ |---|---|---|
37
+ | Histogram | Shape of a single continuous variable's distribution | Comparing two distributions directly — use overlaid density or faceted charts |
38
+ | Box Plot | Comparing distributions across groups; showing median, IQR, outliers | Audiences unfamiliar with statistical notation — explain quartiles in the chart subtitle |
39
+ | Violin Plot | Same as box plot, but when the shape of the distribution matters (bimodal, skewed) | Small samples (n < 30) — the smoothed density curve is misleading |
40
+ | Heatmap | Distribution of a value across two categorical dimensions; calendar patterns | When precise values matter — heatmap encodes value via color, which is imprecise |
41
+
42
+ ### Relationship
43
+
44
+ | Chart type | When to use | When to avoid |
45
+ |---|---|---|
46
+ | Scatter | Correlation between two continuous variables | Overplotting with > 5,000 points — use hexbin or density contours instead |
47
+ | Bubble | Three-variable relationship where the third variable is proportional in magnitude | When bubble areas differ < 2× — the size difference is imperceptible |
48
+ | Chord | Flows or relationships between the same set of entities (e.g., trade between countries) | Directed flows where magnitude matters — Sankey is clearer |
49
+ | Sankey | Directed flows between nodes; volume is encoded in link width | Cyclic flows; more than ~10 nodes (hairball effect) |
50
+ | Network/Force-directed | Topology of connections between nodes; cluster detection | Quantifying relationships — edge weight is visually unreliable |
51
+
52
+ ### Trend
53
+
54
+ | Chart type | When to use | When to avoid |
55
+ |---|---|---|
56
+ | Line | Single or multiple continuous values over time | Unordered categorical data — use bar |
57
+ | Area | Cumulative volume over time; emphasis on magnitude not rate of change | Multiple series with overlapping areas — use line chart with fills instead |
58
+ | Sparkline | Compact trend indicator embedded in a table or KPI card | Any context requiring axis labels or precise value reading |
59
+ | Candlestick | OHLC financial data; price range and direction per period | Non-financial time series — the OHLC convention is opaque to general audiences |
60
+
61
+ ### Progress/Goal
62
+
63
+ | Chart type | When to use | When to avoid |
64
+ |---|---|---|
65
+ | Gauge | Single KPI versus a target or threshold; dashboard hero metric | Multiple gauges side by side — comparison is very hard with radial encodings |
66
+ | Funnel | Conversion or attrition across sequential stages | Stages that are not strictly sequential or mutually exclusive |
67
+
68
+ ### Geographic
69
+
70
+ | Chart type | When to use | When to avoid |
71
+ |---|---|---|
72
+ | Geographic / Choropleth | Value distribution across geographic regions; regional comparison | When region size distorts perception — large low-population regions dominate (use cartogram instead) |
73
+
74
+ ### Project Timelines
75
+
76
+ | Chart type | When to use | When to avoid |
77
+ |---|---|---|
78
+ | Gantt | Task scheduling, duration, and dependency visualization over time | Real-time progress tracking without frequent data updates — stale Gantt charts mislead |
79
+
80
+ ---
81
+
82
+ ## 2. Complete Chart Catalog (25 Types — GDD Decision Format)
83
+
84
+ ### Comparison
85
+
86
+ **Bar (Vertical)**
87
+ Use a vertical bar chart when comparing discrete, unordered categories and the category labels fit horizontally beneath each bar. It is the default choice for most categorical comparison tasks because readers compare bar heights intuitively from a shared baseline. Recommended library: Recharts `<BarChart>` for React. Never use when you have more than 15 categories or when the chart width cannot accommodate all labels without rotation.
88
+
89
+ **Bar (Horizontal)**
90
+ Use a horizontal bar chart when category labels are long (> 15 characters), when rankings are the story, or when you have more than 8 categories. Horizontal orientation gives labels room to breathe and makes rank order easy to read top-to-bottom. Recommended library: Recharts `<BarChart layout="vertical">` for React. Never use when your data represents a time series — line charts handle ordered time data far better.
91
+
92
+ **Bullet Chart**
93
+ Use a bullet chart when you need to show a single measure against one or more qualitative thresholds (poor / satisfactory / good) and a target marker, typically in a KPI or performance dashboard. It was designed by Stephen Few as a compact replacement for gauges and meter charts. Recommended library: Nivo `@nivo/bullet` for React. Never use when the audience needs to compare more than eight metrics simultaneously — the encoding becomes too dense.
94
+
95
+ **Slope Chart**
96
+ Use a slope chart when you want to show how values changed between exactly two time points and which entities rose, fell, or crossed each other. The crossing lines make rank reversal immediately visible. Recommended library: D3 with a custom `line` generator in React. Never use when you have more than two time points or more than ~10 entities — the chart becomes unreadable.
97
+
98
+ ---
99
+
100
+ ### Composition
101
+
102
+ **Pie Chart**
103
+ Use a pie chart when showing how a whole divides into parts, the parts are mutually exclusive and exhaustive, and there are five or fewer slices with meaningfully different sizes. Readers are reliable at judging the largest and smallest slices but not intermediate ones. Recommended library: Recharts `<PieChart>` for React. Never use when you have more than five categories or when precise comparison between slices is required.
104
+
105
+ **Donut Chart**
106
+ Use a donut chart in the same scenarios as a pie chart, with the added benefit that the hollow center can display a summary value (total, percentage of the largest segment, or a label). The reduced ink in the center slightly improves the legibility of the arc. Recommended library: Recharts `<PieChart>` with `innerRadius` set for React. Never use when the center callout number would distract from the part-whole message or when the chart is very small.
107
+
108
+ **Stacked Bar Chart**
109
+ Use a stacked bar chart when you need to show both total magnitude and part-of-whole composition across multiple groups or time points simultaneously. The bottom segment is comparable across groups; interior segments are not — readers cannot align them to a common baseline. Recommended library: Recharts `<BarChart>` with `stackId` for React. Never use when comparing the sizes of interior stack segments is the primary analytical task.
110
+
111
+ **Treemap**
112
+ Use a treemap when showing hierarchical composition and sizes span a wide range — the nested rectangles make relative size comparisons across magnitudes legible at a glance. Treemaps handle dozens to hundreds of leaf nodes without becoming unreadable, provided the labels are sized to fit. Recommended library: Nivo `@nivo/treemap` for React. Never use when the data has fewer than eight leaf nodes (a bar chart communicates the same information with less decoding effort) or when showing change over time.
113
+
114
+ **Sunburst**
115
+ Use a sunburst chart when hierarchical part-of-whole data has two or three meaningful levels and the reader needs to trace the contribution of sub-categories to their parent. Each ring represents one level of the hierarchy. Recommended library: Nivo `@nivo/sunburst` for React. Never use when hierarchy depth exceeds three levels, as inner rings become too small to label legibly and the chart degrades into an art object.
116
+
117
+ **Waterfall Chart**
118
+ Use a waterfall chart when explaining how an initial value reaches a final value through a series of positive and negative contributions — profit-and-loss bridges, budget variance analysis, and step-by-step change attribution are the canonical use cases. Each bar floats from the accumulated prior value. Recommended library: Recharts with custom `<Bar>` using transparent bottom segments to create the floating effect, or Nivo `@nivo/bar` for React. Never use when the intermediate steps are not sequentially meaningful or when the audience cannot tolerate the decoding effort of floating bars.
119
+
120
+ ---
121
+
122
+ ### Distribution
123
+
124
+ **Histogram**
125
+ Use a histogram when revealing the shape of a single continuous variable's distribution — whether it is normal, skewed, bimodal, or has outliers. The key design choice is bin width: too few bins hides structure; too many bins creates noise. Recommended library: Nivo `@nivo/bar` with manually computed bins, or Victory `<VictoryHistogram>` for React. Never use when comparing two distributions on the same axis — overlapping histograms are hard to read; use a ridgeline or faceted approach instead.
126
+
127
+ **Box Plot**
128
+ Use a box plot (box-and-whisker) when comparing the distribution of a continuous variable across multiple groups. It summarizes median, interquartile range (IQR), and outliers in a compact glyph that scales to dozens of groups. Recommended library: Victory `<VictoryBoxPlot>` for React. Never use with audiences unfamiliar with statistical notation — always include a subtitle that explains that the box spans the middle 50% of values.
129
+
130
+ **Violin Plot**
131
+ Treat a violin plot as an enhanced box plot that additionally shows the full density shape of the distribution via a mirrored kernel density estimate. Use it when the distribution shape is the analytical point — bimodality, heavy tails, or gaps in the data that a box plot's five-number summary would hide. Recommended library: D3 with a custom density estimate rendered as a `<path>` in React. Never use with samples smaller than 30 observations — the smoothed curve implies precision the data does not support.
132
+
133
+ **Heatmap**
134
+ Use a heatmap when showing the distribution of a value across two categorical dimensions simultaneously — website traffic by hour and day of week, gene expression across samples and conditions, or feature correlation matrices. Color encodes the value; spatial position encodes the two categories. Recommended library: Nivo `@nivo/heatmap` for React. Never use when the audience needs to read precise values — color is an imprecise channel; pair with tooltips or an adjacent data table.
135
+
136
+ ---
137
+
138
+ ### Relationship
139
+
140
+ **Scatter Plot**
141
+ Use a scatter plot when investigating correlation, clustering, or outliers between two continuous variables. Each point represents one observation; position encodes both values against shared axes. Recommended library: Recharts `<ScatterChart>` for React. Never use when overplotting obscures the pattern — with more than 5,000 points, switch to a hexbin aggregation or 2D density contour chart.
142
+
143
+ **Bubble Chart**
144
+ Use a bubble chart when a third continuous variable can be meaningfully encoded as the area of each scatter point — market share plus revenue plus growth rate, for example. Area encoding is less precise than position, so the third variable should be the least precise claim in the story. Recommended library: Recharts `<ScatterChart>` with a custom dot renderer for React. Never use when the range of the third variable is less than 2× — the size difference is imperceptible and the extra encoding adds confusion without insight.
145
+
146
+ **Chord Diagram**
147
+ Use a chord diagram when showing bidirectional flows or relationships between members of the same set — migration between cities, trade flows between countries, or co-occurrence between categories. The arc length encodes the total flow for each node; the chord width encodes the flow between two specific nodes. Recommended library: D3 `d3-chord` with custom React SVG rendering. Never use when the flows are directed and their asymmetry is the story — Sankey handles directed flows with visible volume much more clearly.
148
+
149
+ **Sankey Diagram**
150
+ Use a Sankey diagram when showing directed flows with volume through a network of nodes — user journey funnels, energy systems, budget allocations, and supply chain flows are classic cases. Link width is proportional to flow volume. Recommended library: Nivo `@nivo/sankey` for React. Never use with cyclic flows or more than approximately ten nodes — the diagram quickly becomes a hairball that defeats the purpose of the visualization.
151
+
152
+ **Network / Force-Directed Graph**
153
+ Use a force-directed network graph when the topology of connections between entities is the story — who is connected to whom, cluster structure, centrality, and isolated nodes. Force simulation positions densely connected clusters near each other. Recommended library: D3 `d3-force` with custom React SVG for full control. Never use when you need to compare edge weights or node values precisely — quantitative encoding via edge thickness or node size is unreliable in a force layout.
154
+
155
+ ---
156
+
157
+ ### Trend
158
+
159
+ **Line Chart**
160
+ Use a line chart when showing how one or more continuous values change over an ordered time series. The connecting line implies continuity between measurements, so only use it when intermediate values would logically exist. Recommended library: Recharts `<LineChart>` for React. Never use for unordered categorical data — a bar chart is correct when there is no meaningful order between data points.
161
+
162
+ **Area Chart**
163
+ Use an area chart when the cumulative volume or magnitude beneath the line is part of the story — total revenue over time, cumulative downloads, or stacked contribution of multiple series. Filling the area below the line emphasizes quantity more than rate of change. Recommended library: Recharts `<AreaChart>` for React. Never use with multiple overlapping series that share the same baseline — the overlaps become confusing; use a line chart with area fills per series that do not overlap, or switch to a stacked area.
164
+
165
+ **Sparkline**
166
+ Use a sparkline as a compact inline trend indicator embedded within a table cell, a KPI card, or dense prose — the shape of the trend is the signal, not individual values. They are designed to be read without axes or labels. Recommended library: Recharts `<LineChart>` at very small dimensions with all axes and padding removed, or Victory `<VictoryLine>` for React. Never use when the reader needs to identify specific values, compare two sparklines precisely, or understand the scale of the change.
167
+
168
+ **Candlestick Chart**
169
+ Use a candlestick chart for financial OHLC (open, high, low, close) data where the price range and direction within each period are both meaningful — daily stock prices, hourly crypto trades, and options expiry analysis. The body color (typically green/red) encodes whether the close was above or below the open. Recommended library: a specialized financial library such as `lightweight-charts` (TradingView), or D3 with custom React SVG for full control. Never use for non-financial time series where the OHLC convention would confuse general audiences who do not know the encoding.
170
+
171
+ ---
172
+
173
+ ### Progress / Goal
174
+
175
+ **Gauge Chart**
176
+ Use a gauge (also called a dial or speedometer chart) for a single KPI that has a meaningful threshold or target — CPU usage, customer satisfaction score, or a completion percentage. The radial encoding is immediately legible to general audiences as a progress metaphor. Recommended library: Nivo `@nivo/pie` with a semi-circle clipping mask, or a custom D3 arc in React. Never use for multiple gauges displayed side by side — radial comparison is cognitively expensive; use a bullet chart array instead.
177
+
178
+ **Funnel Chart**
179
+ Use a funnel chart when showing attrition or conversion across a fixed sequence of stages — e-commerce checkout steps, sales pipeline stages, or onboarding flows. Each stage is narrower than the previous, encoding drop-off volume. Recommended library: Nivo `@nivo/funnel` for React. Never use when the stages are not strictly sequential, not mutually exclusive, or when users can re-enter earlier stages — the funnel metaphor implies a one-way flow and will mislead.
180
+
181
+ ---
182
+
183
+ ### Geographic
184
+
185
+ **Geographic / Choropleth Map**
186
+ Use a choropleth map when comparing a statistical variable across geographic regions — unemployment by county, election results by state, or population density by country. Color encodes the variable; spatial position provides geographic context. Recommended library: D3 with `d3-geo` projections and TopoJSON boundary data, or Nivo `@nivo/geo` for React. Never use when large low-population regions visually dominate the map while small high-population regions are barely visible — this is a known perceptual bias of choropleths; consider a cartogram or a bar chart with a small map inset.
187
+
188
+ ---
189
+
190
+ ### Project Timelines
191
+
192
+ **Gantt Chart**
193
+ Use a Gantt chart when visualizing task scheduling, durations, dependencies, and resource allocation across a project timeline. Horizontal bars represent task duration; vertical position groups tasks by resource or phase. Recommended library: custom D3 rendering or specialized libraries such as `react-google-charts` (Gantt type) for React. Never use when the underlying data is not kept current — a stale Gantt chart actively misleads stakeholders about project status.
194
+
195
+ ---
196
+
197
+ ## 3. Color-Blind-Safe Palettes
198
+
199
+ Approximately 8% of males and 0.5% of females have some form of color vision deficiency. Using a color-blind-safe palette is not optional for any chart that reaches a general audience.
200
+
201
+ ### Okabe-Ito (Categorical — 8 colors)
202
+
203
+ Developed by Masataka Okabe and Kei Ito and published in "Color Universal Design (CUD): How to make figures and presentations that are friendly to colorblind people" (J-Stage, 2008). This palette is distinguishable under all major types of color vision deficiency: deuteranopia, protanopia, tritanopia, and achromatopsia.
204
+
205
+ | Swatch | Name | Hex |
206
+ |---|---|---|
207
+ | Black | Black | `#000000` |
208
+ | Orange | Orange | `#E69F00` |
209
+ | Sky Blue | Sky Blue | `#56B4E9` |
210
+ | Bluish Green | Bluish Green | `#009E73` |
211
+ | Yellow | Yellow | `#F0E442` |
212
+ | Blue | Blue | `#0072B2` |
213
+ | Vermillion | Vermillion | `#D55E00` |
214
+ | Reddish Purple | Reddish Purple | `#CC79A7` |
215
+
216
+ Use Okabe-Ito as the default categorical palette for all new charts unless a client brand palette takes precedence. When brand colors are required, simulate deuteranopia using tools such as Coblis or Viz Palette before shipping.
217
+
218
+ ### Viridis (Sequential — Continuous)
219
+
220
+ Viridis is a perceptually uniform sequential colormap developed by Nathaniel Smith and Stefan van der Walt for matplotlib (SciPy 2015). It is safe for deuteranopia and protanopia, prints legibly in greyscale, and is monotonically increasing in perceived brightness — meaning that higher values are always visually distinct from lower values. Use Viridis for heatmaps, choropleths, and any continuous sequential data.
221
+
222
+ CSS custom property suggestion: use the `viridis` scale from the `d3-scale-chromatic` package — `d3.scaleSequential(d3.interpolateViridis)`.
223
+
224
+ ### Cividis (Sequential — Blue-Yellow Optimized)
225
+
226
+ Cividis is a variant of Viridis specifically optimized for blue-yellow (tritanopia) color blindness, developed by Jamie Nuñez, Christopher Anderton, and Ryan Renslow (PLOS ONE, 2018). It transitions from dark blue through grey to yellow and is designed to appear nearly identical to individuals with and without color vision deficiency. Use Cividis when your audience includes users with tritanopia, or as a general-purpose alternative to Viridis.
227
+
228
+ CSS: `d3.scaleSequential(d3.interpolateCividis)` from `d3-scale-chromatic`.
229
+
230
+ ### Plasma (Sequential — High Contrast)
231
+
232
+ Plasma is a high-contrast perceptually uniform sequential palette that transitions from dark purple through bright orange-yellow. Use Plasma for sequential data where Viridis reads as too green-dominant or where high contrast between low and high values is needed in print. It is safe for deuteranopia and protanopia.
233
+
234
+ CSS: `d3.scaleSequential(d3.interpolatePlasma)` from `d3-scale-chromatic`.
235
+
236
+ ### Red-Green Ban
237
+
238
+ **Never use red and green as the primary visual distinction in any chart.** Red-green color blindness (deuteranopia/protanopia) affects approximately 8% of males. This means that in any reasonably sized user group, a significant fraction of your male users cannot distinguish a chart that uses red for "negative" and green for "positive." Replace red-green with a blue-orange or purple-green pairing, or use position and shape as the primary encoding with color as a secondary channel.
239
+
240
+ ---
241
+
242
+ ## 4. Pie Chart Rules
243
+
244
+ The pie chart is the most misused chart type in business contexts. These rules are non-negotiable.
245
+
246
+ - **Use pie only for part-of-whole data with five or fewer slices.** The human visual system is reliable at reading pie slices only when the slices are few and substantially different in size. Beyond five slices, switch to a horizontal bar chart sorted by value.
247
+ - **Never use 3D pie charts.** The perspective projection warps the apparent size of slices — a slice in the foreground appears larger than an identical slice in the background. A 3D pie chart is not a stylistic choice; it is a lie about the data. Remove it from any design system component library.
248
+ - **For more than five categories, use a bar chart or treemap.** A horizontal bar chart sorted descending gives every category a position on a shared baseline and is orders of magnitude more readable than a twelve-slice pie.
249
+ - **Label slices directly when there are five or fewer slices.** Place the label and value inside or adjacent to each slice. Legends force the reader to shuttle their eyes back and forth between the legend and the chart — this is cognitive overhead that direct labeling eliminates. When slices are too small to label directly, use a leader line.
250
+
251
+ ---
252
+
253
+ ## 5. Axis Conventions
254
+
255
+ Axes are the scaffolding of interpretation. Misusing them is one of the most common ways charts mislead.
256
+
257
+ ### Zero Baseline
258
+
259
+ Always start bar chart and area chart Y-axes at zero. A bar whose height encodes a value depends entirely on that bar's length relative to the baseline — truncating the baseline inflates the visual difference between bars. A chart showing two bars of 98 and 99 that is truncated to start at 97 makes them appear vastly different; starting at zero makes them appear nearly identical, which is the truth. This rule is absolute for bar and area charts.
260
+
261
+ ### Line Chart Truncation Exception
262
+
263
+ Line charts showing change over time may truncate the Y axis when the absolute values are large but the change is small and meaningful — for example, a body temperature chart ranging from 36.0°C to 38.5°C is more useful than one ranging from 0°C to 40°C. **When you truncate a line chart Y-axis, you must include a break indicator (⁃⁃) on the axis to signal that the baseline is not zero.** Without the break indicator, the chart misleads.
264
+
265
+ ### Dual Y-Axis
266
+
267
+ Avoid dual Y-axis charts. A dual Y-axis allows the designer to manipulate the apparent correlation between two variables by independently scaling each axis — any two unrelated trends can be made to appear correlated. There is almost always a better alternative: separate charts sharing an X-axis (small multiples), an index chart normalizing both series to 100 at a common start point, or a scatter plot if correlation is what you are trying to show.
268
+
269
+ ### Log Scale
270
+
271
+ A logarithmic scale is valid and appropriate when data spans multiple orders of magnitude — population by country, income distribution, or exponential growth curves. A log scale compresses the high end and expands the low end, making growth rates comparable across the full range. **Always label a log-scale axis explicitly as "log scale."** Readers who do not notice they are looking at a log axis will dramatically misread the rate of change between data points.
272
+
273
+ ---
274
+
275
+ ## 6. Annotation Patterns
276
+
277
+ Annotations are the editorial layer of a chart — they tell the reader which data points are most important and why.
278
+
279
+ ### Direct Labeling vs. Legend
280
+
281
+ Direct labeling on the chart is more readable than a legend when the chart has five or fewer series. A legend requires the reader to locate the matching color or shape key and then return to the chart; direct labeling at the end of each line or within each bar segment eliminates that round trip. Use a legend only when there are six or more series or when lines overlap so densely that labels cannot be placed without collision.
282
+
283
+ ### Callouts for Notable Data Points
284
+
285
+ Use callout annotations to mark data points with editorial significance — a record high or low, a policy change, an anomaly, a product launch, or an external event that explains a discontinuity. A callout typically consists of a small circle or dot on the data point, a leader line, and a text label. Callout text should be **one sentence maximum**, left-aligned on the callout, and written in plain language that states what happened, not what the reader can already see ("Revenue fell 22% in March after the supply chain disruption" is useful; "Value decreases here" is not).
286
+
287
+ ### Annotation Placement
288
+
289
+ Place annotations so they do not overlap the most important data series. Use white or semi-transparent backgrounds behind annotation text boxes to ensure legibility against the chart background. On small screens, consider reducing annotation density or making annotations accessible via a tooltip rather than always-visible text.
290
+
291
+ ---
292
+
293
+ ## 7. Accessibility
294
+
295
+ Data visualizations present unique accessibility challenges because they communicate through a visual channel that is unavailable to screen reader users and partially unavailable to users with color vision deficiency.
296
+
297
+ ### Data Table Alternative
298
+
299
+ Always provide a data table as an accessible alternative to complex charts. WCAG 1.1.1 (Level A) requires non-text content to have a text alternative that presents the same information. For a line chart, this means an HTML `<table>` with the same data used to generate the chart — it can be visually hidden and shown on demand, included below the chart, or linked as a download. The chart title and description should also be conveyed in the chart's `<title>` and `<desc>` SVG elements or in an `aria-label` on the chart container.
300
+
301
+ ### ARIA Live Regions for Dynamic Charts
302
+
303
+ Charts that update in real time — stock price tickers, live analytics dashboards, server monitoring — must use ARIA live regions to announce changes to screen reader users. Set `aria-live="polite"` on a visually hidden element that receives a text update each time the chart data changes. Use `aria-live="assertive"` only for urgent alerts (threshold breach, system failure). Avoid updating the live region more than once every few seconds, as rapid updates interrupt screen reader speech.
304
+
305
+ ### Keyboard Navigation
306
+
307
+ Interactive charts that support brushing, zooming, or selecting data ranges must be keyboard accessible. The selected data range must have a visible focus ring that meets WCAG 2.4.7 (focus visible). Users should be able to move the selection with arrow keys, reset with Escape, and confirm a selection with Enter. This applies to date range pickers embedded in dashboards, scatter plot lasso selections, and histogram brush controls.
308
+
309
+ ### Sonification
310
+
311
+ Sonification — encoding data as sound (pitch, tempo, or timbre) — is an experimental but promising alternative for screen reader users who cannot interpret visual charts even with text alternatives. Libraries such as Highcharts Sonification Studio and Astronify provide this capability. Sonification is not currently a WCAG requirement, but it is worth noting for products that serve visually impaired users as a primary audience. Do not substitute sonification for a data table; provide both.
312
+
313
+ ---
314
+
315
+ ## 8. Dashboard Patterns
316
+
317
+ A dashboard is a collection of charts, and the design principles that apply to individual charts apply with compounding force to dashboards — bad individual chart choices become bad dashboard experiences.
318
+
319
+ ### Overview First, Filter Late, Drill Down
320
+
321
+ Follow Shneiderman's Visual Information-Seeking Mantra: **overview first, zoom and filter, then details on demand.** The dashboard's first view should give the reader the big picture — total performance, trend direction, anomalies. Filtering controls (date range, segment selector) narrow the overview. Drill-down links or expandable panels reveal underlying detail. Reversing this order — starting with granular data — overwhelms users and prevents them from forming a correct mental model of the system.
322
+
323
+ ### KPI Cards Above the Fold
324
+
325
+ The most important single number belongs above the fold as a KPI card. A well-designed KPI card contains three elements: the **current value** (large, high-contrast), the **trend direction** (up/down arrow with percentage change), and a **comparison to the prior period** (last week, last month, last year). These three elements answer the three questions every stakeholder asks first: what is it, is it good or bad, and is it getting better or worse?
326
+
327
+ ### Progressive Disclosure
328
+
329
+ Structure dashboard information in three layers: **summary** (KPI cards and headline charts above the fold), **detail** (supporting charts visible on scroll), and **raw data** (accessible via a link, export, or drill-down table). This mirrors how users actually read dashboards — most users stop at the summary layer most of the time; power users drill into detail; analysts need the raw data. Putting all three layers on the same screen simultaneously creates visual noise for the majority of users.
330
+
331
+ ### Cognitive Load Budget
332
+
333
+ Apply a strict cognitive load budget above the fold: **no more than five distinct visual elements** (KPI cards, charts, filter controls) should compete for attention in the initial viewport. Every additional element above five increases cognitive load non-linearly — users experience "dashboard blindness" and stop reading the dashboard at all. If you have eight KPIs, group them into two rows of four with clear visual hierarchy that directs attention to the top two. If you have twelve charts, use tabs or sections to reveal them progressively rather than displaying them simultaneously.
@@ -0,0 +1,245 @@
1
+ # Form Patterns
2
+
3
+ Forms are one of the highest-friction surfaces in any product. Every unnecessary click, ambiguous label, or poorly-timed error message is a conversion lost or a user abandoned mid-task. The patterns below are grounded in empirical research — primarily Luke Wroblewski's eye-tracking studies, WCAG 2.1 requirements, and NCSC/NIST guidance on authentication UX.
4
+
5
+ ---
6
+
7
+ ## 1. Label Position
8
+
9
+ Wroblewski's eye-tracking research measured the number of eye fixations required to move from label to field across the three common label placements. The findings are decisive: top-aligned labels are fastest because the eye travels in one direction — down — without a horizontal context switch.
10
+
11
+ **Top-aligned labels** are the default for most forms. Completion time is fastest because the label and input form a single vertical unit. They also accommodate longer translated strings without breaking layout, making them the correct default for internationalised products. Use top-aligned labels whenever form complexity is moderate to high or field types are mixed.
12
+
13
+ **Left-aligned labels** create the slowest completion time because the eye must saccade horizontally from label to field on every row. They earn their place only when scannability of values matters more than speed — settings pages, data-entry tables, or read-heavy forms where users compare label and value together. In these contexts the horizontal alignment aids review, not input.
14
+
15
+ **Floating labels (Material 3 style)** are an acceptable middle ground when screen real estate is severely constrained. The label begins as visible hint text above the field and remains visible (shrunk, repositioned) after the user starts typing. This pattern is distinct from — and incompatible with — placeholder-as-label. Never use placeholder text as the sole label: when the field receives focus the placeholder disappears, leaving the user to recall what was asked. This is a WCAG 2.1 failure under criterion 1.3.5 (Identify Input Purpose) and a general usability failure on any form longer than three fields.
16
+
17
+ | Label position | Completion speed | Best use case |
18
+ |---|---|---|
19
+ | Top-aligned | Fastest | Most forms; mixed field types; long forms |
20
+ | Left-aligned | Slowest | Settings pages; data comparison; values matter |
21
+ | Floating (Material 3) | Medium | Space-constrained mobile forms |
22
+ | Placeholder-only | — | **Never** — WCAG 1.3.5 failure |
23
+
24
+ ---
25
+
26
+ ## 2. Inline Validation Timing
27
+
28
+ The timing of inline validation determines whether it helps or hinders. Validate too early and you penalise users for typing incomplete but valid input. Validate too late and users reach the submit button without knowing several fields are wrong.
29
+
30
+ **On-submit only** carries the lowest cognitive load during form completion and is appropriate for short forms (three fields or fewer). The cost is UX debt on long forms: when multiple fields fail at once, the user must scroll up to find errors, fix one, scroll back, and repeat. Provide an error summary at the top if using submit-only validation on long forms (see Section 3).
31
+
32
+ **On-blur (field exit)** is the recommended default for most forms. Validation fires after the user leaves the field, not while they are in it. This prevents the jarring experience of an error appearing mid-keystroke. The critical rule: never validate on first focus — only after the field has been blurred at least once. A pristine, untouched field should never show an error state.
33
+
34
+ **On-change (real-time)** is appropriate for two specific cases: password strength meters and character counters. It is not appropriate for format validation such as email addresses. Validating email format on every keystroke flags `hello@` as invalid before the user has finished typing the domain — a false negative that erodes trust in the form.
35
+
36
+ Never show a red error state before the user has had a realistic opportunity to complete the field. The error state is a signal that something is wrong; triggering it prematurely teaches users to ignore it.
37
+
38
+ | Timing | When to use | When to avoid |
39
+ |---|---|---|
40
+ | On-submit | Short forms (≤ 3 fields) | Long multi-section forms |
41
+ | On-blur | Default for most fields | — |
42
+ | On-change | Password strength, character count | Format validation (email, phone) |
43
+
44
+ ---
45
+
46
+ ## 3. Error Placement and Recovery Copy
47
+
48
+ Errors placed far from their source — in a top banner, a modal, or a footer — force the user to map the error message back to the problematic field. Errors belong immediately below the field they describe, appearing between the field and the next element in the flow.
49
+
50
+ **Visual treatment**: error messages must never rely on color alone. A red border communicates nothing to users with red-green color deficiency. Use an error icon alongside the message text. The field border color change is acceptable as a supplemental indicator, not the primary one.
51
+
52
+ **Copy quality matters enormously.** "Invalid input" is useless. The error message must name what went wrong and specify how to fix it. Write the copy in plain language from the user's perspective:
53
+
54
+ | Poor copy | Better copy |
55
+ |---|---|
56
+ | Invalid input | Email must include an @ symbol |
57
+ | Password error | Password must be at least 8 characters |
58
+ | Required field | Enter your first name to continue |
59
+ | Invalid date | Enter a date in DD/MM/YYYY format |
60
+
61
+ **Focus management on submit**: when a form submits with errors, move programmatic focus to the first error field or to an error summary element. Leaving focus on the submit button and expecting the user to visually scan for errors is a significant accessibility failure and a poor experience on any device.
62
+
63
+ **Error summary for long forms**: any form with more than five fields should include an error summary at the top of the form when the user attempts to submit. The summary lists each error with a jump-link that moves focus directly to the relevant field. The summary element should receive focus automatically on submit-with-errors. This pattern is required for WCAG 2.4.3 (Focus Order) on complex forms.
64
+
65
+ ```html
66
+ <div role="alert" aria-labelledby="error-summary-title" tabindex="-1">
67
+ <h2 id="error-summary-title">There are 3 errors in this form</h2>
68
+ <ul>
69
+ <li><a href="#email">Email must include an @ symbol</a></li>
70
+ <li><a href="#phone">Enter a valid phone number</a></li>
71
+ <li><a href="#dob">Date of birth must be in the past</a></li>
72
+ </ul>
73
+ </div>
74
+ ```
75
+
76
+ ---
77
+
78
+ ## 4. Required Field Conventions
79
+
80
+ Marking required fields unambiguously prevents submission errors and sets accurate expectations before the user invests time in a form.
81
+
82
+ The **asterisk (*) convention** is the web default. Mark every required field with `*` and place the legend "* Required" near the top of the form, before the first field. Users arriving mid-page may not see a legend placed at the bottom.
83
+
84
+ The **"(optional)" alternative** is better when most fields are required and only a few are not. Marking three optional fields "(optional)" is less visual noise than marking fifteen fields with `*`. Choose one convention per form — never mix both. A form that marks some fields `*` and labels others "(optional)" implies that unlabelled fields are neither required nor optional, which is simply confusing.
85
+
86
+ Regardless of which visual convention is used, every required field must carry `aria-required="true"` or the native `required` attribute. Screen readers announce the required state from these attributes, not from the visible asterisk.
87
+
88
+ ```html
89
+ <!-- Native required attribute (preferred) -->
90
+ <input type="email" id="email" name="email" required>
91
+
92
+ <!-- Or explicit ARIA -->
93
+ <input type="text" id="name" name="name" aria-required="true">
94
+ ```
95
+
96
+ ---
97
+
98
+ ## 5. Multi-Step Forms
99
+
100
+ Multi-step forms break long processes into manageable stages, but they introduce navigation complexity that must be managed explicitly. A user who does not know how many steps remain cannot calibrate effort and is more likely to abandon.
101
+
102
+ **Show total step count upfront** and maintain it throughout. "Step 2 of 4" gives the user a completion model. Never add steps mid-flow; if a conditional step becomes necessary, it must have been accounted for in the total from the beginning. Surprise steps feel like bait-and-switch.
103
+
104
+ **Preserve state between steps** unconditionally. Browser back must restore the previous step with all previously-entered values intact. Losing data on back-navigation is one of the most damaging patterns in multi-step forms — it destroys user trust and forces re-entry of work already done. Use session storage, URL state, or in-memory state managed at the form's root level.
105
+
106
+ **Allow non-linear completion where the domain permits.** If a user wants to skip to step 3 and complete step 2 later, let them. Stepped progress indicators (like a horizontal stepper component) should be interactive links, not decorative labels, unless there is a hard dependency that makes out-of-order completion genuinely impossible.
107
+
108
+ **Summary step before final submission.** Any multi-step form that results in a consequential action — purchase, account creation, booking — should include a review step that shows all entered values before the commit action. The CTA on the summary step should name the action ("Place order", "Create account") not just "Submit".
109
+
110
+ ---
111
+
112
+ ## 6. Autofill Hints — `autocomplete` Taxonomy
113
+
114
+ The `autocomplete` attribute tells the browser — and password managers, autofill services, and mobile OS keyboards — exactly what category of data a field expects. Proper use of `autocomplete` tokens reduces form completion time by 15–30% in controlled studies, primarily because browsers and password managers can populate multiple fields in a single tap. Always pair each token with the correct `input type`.
115
+
116
+ | Token | Meaning | Recommended `input type` |
117
+ |---|---|---|
118
+ | `name` | Full name | `text` |
119
+ | `email` | Email address | `email` |
120
+ | `tel` | Full telephone number | `tel` |
121
+ | `username` | Account username | `text` or `email` |
122
+ | `current-password` | Existing password (login) | `password` |
123
+ | `new-password` | New or changed password | `password` |
124
+ | `street-address` | Full street address (multi-line) | `text` or `textarea` |
125
+ | `postal-code` | Postal / zip code | `text` |
126
+ | `country` | Country code (ISO 3166-1 alpha-2) | `select` |
127
+ | `cc-number` | Credit/debit card number | `text` (`inputmode="numeric"`) |
128
+ | `cc-exp` | Card expiry (MM/YY) | `text` (`inputmode="numeric"`) |
129
+ | `cc-csc` | Card security code | `text` (`inputmode="numeric"`) |
130
+ | `bday` | Full date of birth | `date` |
131
+ | `sex` | Gender identity | `select` or `text` |
132
+ | `language` | Preferred language | `select` |
133
+ | `url` | Web address | `url` |
134
+
135
+ For address fields that are split across multiple inputs, use the sub-tokens (`address-line1`, `address-line2`, `address-level1` for state/province, `address-level2` for city) rather than the generic `street-address` token.
136
+
137
+ ---
138
+
139
+ ## 7. Input Mode and Enter Key Hints
140
+
141
+ On mobile devices, `inputmode` controls which virtual keyboard the OS presents, independently of the input's semantic type. `enterkeyhint` controls the label shown on the Enter/Go key. Both attributes are pure UX signals — they carry no validation meaning — and they cost nothing to add.
142
+
143
+ ### `inputmode` values
144
+
145
+ | Value | Keyboard shown | Use for |
146
+ |---|---|---|
147
+ | `none` | No keyboard | Fields with custom picker UI (date pickers, custom selects) |
148
+ | `text` | Standard keyboard | Default; general text |
149
+ | `decimal` | Numeric with decimal separator | Prices, measurements, quantities with fractions |
150
+ | `numeric` | Numeric only (0–9) | Quantities, PIN codes, verification codes |
151
+ | `tel` | Phone dialpad | Phone numbers, even when `type="text"` |
152
+ | `email` | Keyboard with @ and . prominent | Email; `type="email"` sets this implicitly |
153
+ | `search` | Keyboard with Search action | Search fields |
154
+ | `url` | Keyboard with / and . prominent | URLs; `type="url"` sets this implicitly |
155
+
156
+ ### `enterkeyhint` values
157
+
158
+ | Value | Key label shown | Use for |
159
+ |---|---|---|
160
+ | `enter` | Return / Enter | Multi-line text areas; default where no hint applies |
161
+ | `done` | Done | Last field in a form; closes keyboard |
162
+ | `go` | Go | Single-field forms that submit on Enter |
163
+ | `next` | Next | Fields where Enter moves to the next input |
164
+ | `previous` | Previous | Back-navigation within a multi-step form |
165
+ | `search` | Search | Search fields |
166
+ | `send` | Send | Message composition fields |
167
+
168
+ ```html
169
+ <input
170
+ type="text"
171
+ inputmode="numeric"
172
+ enterkeyhint="next"
173
+ autocomplete="cc-number"
174
+ placeholder="Card number"
175
+ >
176
+ ```
177
+
178
+ ---
179
+
180
+ ## 8. Password UX
181
+
182
+ Password fields carry more UX debt than almost any other input type, largely due to outdated security theatre that made passwords harder to use without making them more secure.
183
+
184
+ **Show/hide toggle** is mandatory on any password field. The eye icon is the standard affordance. Both states must have accessible labels: `aria-label="Show password"` and `aria-label="Hide password"`. The toggle should be positioned as a button inside the trailing edge of the input, using `type="button"` to prevent accidental form submission.
185
+
186
+ **Never block paste** on password fields. The UK National Cyber Security Centre (NCSC) explicitly recommends against paste-blocking. The rationale is simple: blocking paste discourages the use of password managers, which in turn pushes users toward shorter, simpler, more memorable — and therefore weaker — passwords. Paste-blocking does not prevent any known attack vector on the server side. Remove any `onpaste="return false"` or equivalent.
187
+
188
+ **Password strength meters** belong on new-password creation flows only. Displaying a strength meter on a login form reveals information about the stored password and adds noise to a flow where speed matters. Use `zxcvbn` or an equivalent entropy-based library rather than simple length/character-class rules, which users learn to game (e.g., "Password1!" satisfies most naive rules but is trivially guessable).
189
+
190
+ **Show requirements before the user types**, not as errors after they fail. If a password must be at least 10 characters and contain a number, display those requirements beneath the field before the field receives focus. The moment requirements appear only as error messages after submission, the form has trained the user to fail before they can succeed.
191
+
192
+ ```html
193
+ <div class="field">
194
+ <label for="new-password">Create password</label>
195
+ <div class="input-with-toggle">
196
+ <input type="password" id="new-password" autocomplete="new-password" aria-describedby="pw-requirements">
197
+ <button type="button" aria-label="Show password"><!-- eye icon --></button>
198
+ </div>
199
+ <ul id="pw-requirements" class="requirements">
200
+ <li>At least 10 characters</li>
201
+ <li>At least one number or symbol</li>
202
+ </ul>
203
+ </div>
204
+ ```
205
+
206
+ ---
207
+
208
+ ## 9. Consent, Confirmation, and Destructive-Confirmation
209
+
210
+ These three patterns all involve the user acknowledging an outcome, but they operate at different risk levels and require different interaction costs to match.
211
+
212
+ **Consent checkboxes** govern communication preferences and data use. For marketing communications, the checkbox must be unchecked by default — opt-in is required under GDPR and comparable legislation in most jurisdictions. Pre-checked opt-out is only permissible for certain transactional communications or in jurisdictions that explicitly permit it; assume opt-in required unless legal has confirmed otherwise. The checkbox label must be specific about what the user is consenting to — "I agree to receive marketing emails from Acme Ltd." rather than "I accept the terms."
213
+
214
+ **Confirmation dialogs** are appropriate for irreversible actions that affect data the user owns — deleting a file, cancelling a subscription, archiving a project. The confirmation dialog must state exactly what will happen. "Are you sure?" is not a confirmation. "Delete the project 'Website Redesign'? This cannot be undone." is a confirmation. The destructive action button should be visually distinct (typically red or a warning tone) and should not be the default focused element.
215
+
216
+ **Destructive-confirmation with typed phrase** applies to catastrophic, irreversible operations: deleting an account, purging all data, permanently revoking access. Require the user to type a specific phrase — the account name, the word "DELETE", the number of items being erased — before the action becomes available. This pattern exists not to prevent accidents but to ensure the user is making a conscious, deliberate decision. GitHub, Heroku, and most infrastructure tools use this pattern for account deletion. The required phrase should be shown plainly; do not require the user to guess it.
217
+
218
+ | Risk level | Pattern | Example |
219
+ |---|---|---|
220
+ | Low — reversible | None needed | Moving a file to trash |
221
+ | Medium — data loss possible | Confirmation dialog with specific text | Deleting a saved draft |
222
+ | High — irreversible | Dialog + destructive button style | Cancelling a paid subscription |
223
+ | Critical — catastrophic | Dialog + type-to-confirm phrase | Deleting an account and all its data |
224
+
225
+ ---
226
+
227
+ ## 10. CAPTCHA Ethics and Fallbacks
228
+
229
+ CAPTCHA presents a genuine tension: friction added to stop bots is friction experienced by every human user, disproportionately by users with cognitive and motor disabilities.
230
+
231
+ **Invisible CAPTCHA v3** (Google reCAPTCHA v3, Cloudflare Turnstile, hCaptcha Invisible) is the preferred approach. These services score user behaviour in the background and surface a challenge only when the risk score exceeds a threshold. Typical deployments have challenge rates under 1% for real users. There is no visible puzzle, no audio fallback needed for the happy path.
232
+
233
+ **When a visible challenge is unavoidable**, WCAG 1.1.1 requires a non-visual alternative. Every visual CAPTCHA must have an audio alternative that is solvable with a screen reader and no visual ability. Text-based CAPTCHAs distorted beyond normal variance effectively exclude users with dyslexia and cognitive disabilities — treat this as a legal and ethical risk, not just a UX inconvenience.
234
+
235
+ **Time-limited CAPTCHAs** — those that expire while a slow or motor-impaired user is completing them — are inaccessible by design and should never be used. If a CAPTCHA session can time out, the user must be able to request a refresh without losing their form data.
236
+
237
+ **Progressive trust** is the most human approach for authenticated flows. A logged-in user with a verified email and account history presents a negligible bot risk. Do not require CAPTCHA from authenticated users unless there is a specific elevated-risk action (e.g., a bulk API call or mass send). Reserve CAPTCHA friction for unauthenticated, rate-limited, or anomalous-behaviour scenarios.
238
+
239
+ | Approach | User friction | Accessibility | When to use |
240
+ |---|---|---|---|
241
+ | Invisible CAPTCHA v3 (Turnstile, reCAPTCHA v3) | None | Full | Default for public forms |
242
+ | Visible challenge with audio fallback | Medium | Conditional (audio required) | High-risk unauthenticated flows |
243
+ | Progressive trust (authenticated) | None | Full | Logged-in users with account history |
244
+ | Time-limited CAPTCHA | High | Inaccessible | **Never** |
245
+ | Inaccessible visual-only CAPTCHA | High | None | **Never** |