Accessibility Annotations
Annotate Figma screens with accessibility (AX) annotations so engineers know the reading order, focus order, roles, labels, and alt text for every element.
Work is Figma-first: use the annotation library configured for the project. Never invent components or draw homemade highlight shapes.
Project configuration
This skill is design-system agnostic. Resolve these values before the first write, from the project handoff, the repo, or by asking once:
| Setting |
How to resolve |
Fallback |
| Annotation library |
Handoff Annotation library field, or the AX library already published to the target Figma file |
Ask the user for the library name/URL |
| Component names |
Inspect the library's component sets in the file |
Order, Button, Image, Role Value Label, More info |
| Brand font |
The font used by the library's text layers |
Detect at runtime; see figma-tooling.md for the font-swap fallback |
| AX region |
Handoff AX region, or the page/section holding the annotated screens |
Ask which section to annotate |
| Signed-off templates |
Handoff template table |
The user's most recently corrected screen |
If the library names components differently (for example Focus Order instead of Order), map them once and record the mapping in the handoff. Everything else in this skill stays the same.
Before you start
- Load your environment's Figma write skill (for example
figma-use) before every Figma write call.
- Read the project handoff if one exists — it is the canonical status and lists signed-off templates. See handoff-template.md.
- Confirm the section/screen to annotate. Prefer one screen at a time; wait for user QA before applying to sibling screens.
- Open the matching user-corrected pattern (see patterns.md) and clone from it. Do not invent denser layouts.
Workflow
Task progress:
- [ ] Identify section + screens
- [ ] Pick pattern (A–I) from the signed-off template
- [ ] Inspect target nodes (texts, controls, existing AX)
- [ ] Clone library / canvas instances (never homemade shapes)
- [ ] Place orders + callouts (gutters, no stacking)
- [ ] Screenshot-verify
- [ ] Update handoff status
- [ ] Stop for user QA
Process rules
- Sequential Figma writes only — never run parallel write calls on the same file.
- After the user corrects something, inspect their nodes before touching siblings — their edit is the new source of truth.
- Clone pre-labeled instances instead of editing text properties on a fresh library instance.
- If the brand font blocks
appendChild or text edits: swap the text to a safe font (for example Inter) → reparent/edit → restore original fills.
- Parent annotations to the section (or a stable overlay), not deep inside screen chrome, when overlays get messy.
- Sibling state screens can be leaner — only annotate what is new; shared chrome lives on the primary screen.
- Prefer less clutter. Never stack annotations on top of each other.
Critical rules (non-negotiable)
Image ≠ Button
| Use case |
Component |
Label |
| Real controls (Back, Close, CTAs, Filters…) |
Button |
Button label= "…" |
| Logos / hero / decorative / empty illustrations |
Image |
Alt="" (or a filled alt) |
- Never put
Alt="" on a Button.
- Image/Button label text must keep its original fill colour after any font swap.
Button ≠ Role (no doubles)
- Button = named actions (Close, Back, Clear filters, Try again, …).
- Role = richer traits (accordion, tappable teaser, first card in a grid, filter/checkbox/radio/dismiss chips) and no Button on that control.
- Never pair Button + Role on the same control.
Order markers
- Reading order (gray) = text only. Tab order (red) = reading + focus.
- One continuous number stream across reading and tab markers.
- Default: markers in a side gutter. On-element only when side placement is ambiguous (for example chip grids).
- A single element gets no order markers at all — there is nothing to sequence. Add orders only when the target holds several elements to sequence, or when the user asks for order explicitly.
Single element (component docs)
Annotating one component or card is not annotating a screen. Keep it to the semantics of that element:
| Include |
Skip |
Image Alt="" on every decorative icon or logo inside it |
Reading and tab/focus order markers |
One Role, Value, Label box: Role, Label, short Info, AX Hint |
Highlight rectangles around the element, even library ones |
| — |
Note/comment cards that restate what the Role box already says |
Keep Info to one short sentence (for example Entire card is one tappable element.). State wording such as out of stock or disabled belongs in the Label, not in Info.
Placement
- Keep callouts next to their targets; Callout Direction must point at the real control.
- Roles in side gutters; if the left is tight, use the right. Stagger Y.
- Keep Button/Image/Role callouts off screen content when they would hide UI.
- No homemade highlight rectangles, and no library rectangles either unless the user asks. Never use one to group a single element.
- No documentation-only More info notes. Exception: Pattern H Shimmer.
Loading / shimmer (Pattern H)
One More info table — not per-skeleton order markers:
| Prop |
Value |
| Type |
More Info |
| State |
Collapsed |
| Callout Direction |
Left (box to the right of the skeleton) |
| Heading |
Shimmer |
| Description |
Label : "Content is loading" |
Pattern picker (quick)
| Screen type |
Pattern |
Clone mindset |
| Simple content + CTAs / dialogs |
A |
Reading on title/body + Tab on CTAs + Button |
| Onboarding / stories step |
B |
Stories chrome + content + Back/Next Buttons |
| Feed / long scroll |
C |
Filters/chips get Tab; logos are Image; no carousel chrome orders |
| List + logos |
D |
Back Button; row Tabs; logo Image; one Role on the first row |
| Card grid subpage |
E / E+ |
Back; title Reading; one Tab per card; Role on first card; hero Image if present |
| Card / detail sheet |
F |
Side orders; Buttons for CTAs; Role only for accordion |
| Whole teaser card |
G |
One Role (Direction Left, Value off); logo Images; no separate CTA Button |
| Loading skeleton |
H |
More info Shimmer only |
| Filter sheets / search chips |
I |
Chip/checkbox/radio/dismiss Roles; CTA Buttons; no highlight rectangles |
Pattern detail: patterns.md.
Component kit and tooling gotchas: figma-tooling.md.
Handoff format for multi-session work: handoff-template.md.
Role label recipes (filters)
| Control |
Role |
Label example |
Value |
Hint |
| Toggle filter chip |
Button |
One out of seven. <Filter name> |
Selected / Unselected |
Double tap to select / unselect |
| Category chip |
Button |
One out of five. <Category> |
Selected / Unselected |
Double tap to toggle |
| Sort accordion |
Button |
Sort by |
Collapsed / Expanded |
Double tap to expand / collapse |
| Checkbox row |
Check box |
One out of four. <Option> |
Checked / Not checked |
Double tap to toggle |
| Radio row |
Radio Button |
One out of four. <Option> |
Selected / Unselected |
Double tap to toggle |
| Dismissible chip |
Button |
One out of three. <Value>. Delete icon. |
- |
Double tap to dismiss |
Teaser card (Pattern G) checklist
- The whole card is one Role — not a separate CTA Button.
- Direction Left; Value off.
- Label is the full spoken string (title, price/summary, every tag, in visual order).
- Info is one short sentence, for example
Entire card is one tappable element.
- Hint is
Double tap to activate.
- Logos and tag icons inside the card → Image
Alt=""; skip +N overflow chips.
- When the card is the whole request: no order markers, no rectangle, no note card.
Figma plugin constraints
- Switch pages with the async page API only, and at most one page switch per call.
- Failed scripts are atomic — diagnose and fix, then retry. Do not blind-retry.
- Do not rely on toast notifications; always return the IDs of created or mutated nodes.
- Do not rely on variable/brand fonts loading successfully for text property writes.
Done criteria (per screen)
1---2name: accessibility-annotations3description: Annotate Figma UI screens with accessibility annotations — reading order, tab/focus order, Button, Image alt, Role/Value/Label and More info callouts — using the annotation library configured for the project. Use when asked for accessibility annotations, AX annotations, a11y markup in Figma, reading or focus order, screen reader labels for designs, or to continue an accessibility annotation handoff.4---56# Accessibility Annotations78Annotate Figma screens with accessibility (AX) annotations so engineers know the reading order, focus order, roles, labels, and alt text for every element.910Work is **Figma-first**: use the annotation library configured for the project. Never invent components or draw homemade highlight shapes.1112## Project configuration1314This skill is design-system agnostic. Resolve these values before the first write, from the project handoff, the repo, or by asking once:1516| Setting | How to resolve | Fallback |17|---------|----------------|----------|18| Annotation library | Handoff `Annotation library` field, or the AX library already published to the target Figma file | Ask the user for the library name/URL |19| Component names | Inspect the library's component sets in the file | `Order`, `Button`, `Image`, `Role Value Label`, `More info` |20| Brand font | The font used by the library's text layers | Detect at runtime; see [figma-tooling.md](figma-tooling.md) for the font-swap fallback |21| AX region | Handoff `AX region`, or the page/section holding the annotated screens | Ask which section to annotate |22| Signed-off templates | Handoff template table | The user's most recently corrected screen |2324If the library names components differently (for example `Focus Order` instead of `Order`), map them once and record the mapping in the handoff. Everything else in this skill stays the same.2526## Before you start27281. Load your environment's Figma write skill (for example `figma-use`) before every Figma write call.292. Read the project handoff if one exists — it is the canonical status and lists signed-off templates. See [handoff-template.md](handoff-template.md).303. Confirm the section/screen to annotate. Prefer **one screen at a time**; wait for user QA before applying to sibling screens.314. Open the matching user-corrected pattern (see [patterns.md](patterns.md)) and clone from it. Do not invent denser layouts.3233## Workflow3435```36Task progress:37- [ ] Identify section + screens38- [ ] Pick pattern (A–I) from the signed-off template39- [ ] Inspect target nodes (texts, controls, existing AX)40- [ ] Clone library / canvas instances (never homemade shapes)41- [ ] Place orders + callouts (gutters, no stacking)42- [ ] Screenshot-verify43- [ ] Update handoff status44- [ ] Stop for user QA45```4647### Process rules48491. **Sequential Figma writes only** — never run parallel write calls on the same file.502. After the user corrects something, **inspect their nodes** before touching siblings — their edit is the new source of truth.513. Clone **pre-labeled** instances instead of editing text properties on a fresh library instance.524. If the brand font blocks `appendChild` or text edits: swap the text to a safe font (for example Inter) → reparent/edit → restore original fills.535. Parent annotations to the **section** (or a stable overlay), not deep inside screen chrome, when overlays get messy.546. Sibling state screens can be **leaner** — only annotate what is new; shared chrome lives on the primary screen.557. Prefer **less clutter**. Never stack annotations on top of each other.5657## Critical rules (non-negotiable)5859### Image ≠ Button6061| Use case | Component | Label |62|----------|-----------|-------|63| Real controls (Back, Close, CTAs, Filters…) | **Button** | `Button label= "…"` |64| Logos / hero / decorative / empty illustrations | **Image** | `Alt=""` (or a filled alt) |6566- Never put `Alt=""` on a Button.67- Image/Button label text must keep its original fill colour after any font swap.6869### Button ≠ Role (no doubles)7071- **Button** = named actions (Close, Back, Clear filters, Try again, …).72- **Role** = richer traits (accordion, tappable teaser, first card in a grid, filter/checkbox/radio/dismiss chips) **and** no Button on that control.73- Never pair Button + Role on the same control.7475### Order markers7677- **Reading order (gray)** = text only. **Tab order (red)** = reading + focus.78- **One continuous number stream** across reading and tab markers.79- Default: markers in a **side gutter**. On-element only when side placement is ambiguous (for example chip grids).80- **A single element gets no order markers at all** — there is nothing to sequence. Add orders only when the target holds several elements to sequence, or when the user asks for order explicitly.8182### Single element (component docs)8384Annotating one component or card is not annotating a screen. Keep it to the semantics of that element:8586| Include | Skip |87|---------|------|88| `Image` `Alt=""` on every decorative icon or logo inside it | Reading and tab/focus order markers |89| One `Role, Value, Label` box: Role, Label, short Info, AX Hint | Highlight rectangles around the element, even library ones |90| — | Note/comment cards that restate what the Role box already says |9192Keep Info to one short sentence (for example `Entire card is one tappable element.`). State wording such as out of stock or disabled belongs in the Label, not in Info.9394### Placement9596- Keep callouts **next to** their targets; Callout Direction must point at the real control.97- Roles in side gutters; if the left is tight, use the right. Stagger Y.98- Keep Button/Image/Role callouts **off** screen content when they would hide UI.99- No homemade highlight rectangles, and no library rectangles either unless the user asks. Never use one to group a single element.100- No documentation-only More info notes. Exception: **Pattern H Shimmer**.101102### Loading / shimmer (Pattern H)103104One More info table — not per-skeleton order markers:105106| Prop | Value |107|------|-------|108| Type | More Info |109| State | Collapsed |110| Callout Direction | Left (box to the right of the skeleton) |111| Heading | `Shimmer` |112| Description | `Label : "Content is loading"` |113114## Pattern picker (quick)115116| Screen type | Pattern | Clone mindset |117|-------------|---------|---------------|118| Simple content + CTAs / dialogs | **A** | Reading on title/body + Tab on CTAs + Button |119| Onboarding / stories step | **B** | Stories chrome + content + Back/Next Buttons |120| Feed / long scroll | **C** | Filters/chips get Tab; logos are Image; no carousel chrome orders |121| List + logos | **D** | Back Button; row Tabs; logo Image; one Role on the first row |122| Card grid subpage | **E / E+** | Back; title Reading; one Tab per card; Role on first card; hero Image if present |123| Card / detail sheet | **F** | Side orders; Buttons for CTAs; Role only for accordion |124| Whole teaser card | **G** | One Role (Direction Left, Value off); logo Images; no separate CTA Button |125| Loading skeleton | **H** | More info Shimmer only |126| Filter sheets / search chips | **I** | Chip/checkbox/radio/dismiss Roles; CTA Buttons; no highlight rectangles |127128Pattern detail: [patterns.md](patterns.md).129Component kit and tooling gotchas: [figma-tooling.md](figma-tooling.md).130Handoff format for multi-session work: [handoff-template.md](handoff-template.md).131132## Role label recipes (filters)133134| Control | Role | Label example | Value | Hint |135|---------|------|---------------|-------|------|136| Toggle filter chip | Button | `One out of seven. <Filter name>` | Selected / Unselected | Double tap to select / unselect |137| Category chip | Button | `One out of five. <Category>` | Selected / Unselected | Double tap to toggle |138| Sort accordion | Button | `Sort by` | Collapsed / Expanded | Double tap to expand / collapse |139| Checkbox row | Check box | `One out of four. <Option>` | Checked / Not checked | Double tap to toggle |140| Radio row | Radio Button | `One out of four. <Option>` | Selected / Unselected | Double tap to toggle |141| Dismissible chip | Button | `One out of three. <Value>. Delete icon.` | `-` | Double tap to dismiss |142143## Teaser card (Pattern G) checklist1441451. The whole card is one Role — not a separate CTA Button.1462. Direction **Left**; Value **off**.1473. Label is the full spoken string (title, price/summary, every tag, in visual order).1484. Info is one short sentence, for example `Entire card is one tappable element.`1495. Hint is `Double tap to activate`.1506. Logos and tag icons inside the card → Image `Alt=""`; skip `+N` overflow chips.1517. When the card is the whole request: no order markers, no rectangle, no note card.152153## Figma plugin constraints154155- Switch pages with the async page API only, and at most one page switch per call.156- Failed scripts are atomic — diagnose and fix, then retry. Do not blind-retry.157- Do not rely on toast notifications; always return the IDs of created or mutated nodes.158- Do not rely on variable/brand fonts loading successfully for text property writes.159160## Done criteria (per screen)161162- [ ] Correct pattern applied; cloned from the signed-off template when one exists163- [ ] Image vs Button correct; no Button+Role doubles164- [ ] Orders continuous; gutters clean; no stacking165- [ ] Callouts close to targets with the correct Direction166- [ ] Screenshot looks clean next to neighbouring screens167- [ ] Handoff updated; waiting on user QA before siblings