Skip to main content
0
🔄

The Design Spec Translator

Turns a designer's Figma spec into an accessibility-first implementation note for devs.

Rating

0.0

Votes

0

score

Downloads

0

total

Price

Free

No login needed

Works With

ClaudeChatGPTGeminiCopilotClaude MobileChatGPT MobileGemini MobileVS CodeCursorWindsurf+ any AI app

About

There's a moment in every product team where a designer hands a spec to a developer and the accessibility layer gets lost. The Figma file has layouts, colors, typography, states — and almost never has the thing a developer needs: which role is this, what happens on focus, what keys operate it, does the motion respect reduced-motion, what's the dark-mode pairing. The developer implements what they see, ships, and six months later someone files a bug that says "this menu isn't keyboard-accessible."

This skill closes that gap. The user pastes a spec — Figma description, design doc, screenshot with annotations, whatever form it takes — and Claude produces an accessibility-first implementation note: the ARIA roles, focus order, keyboard handlers, state announcements, motion preferences, and dark-mode token mappings the developer needs. Not a rewrite of the spec; a companion document that lives next to it.

The procedure has six steps, one per concern. Claude reads the spec, identifies each interactive and semantic element, and produces a note that names the role (native element preferred, ARIA if no native fits), the keyboard model (what keys do what), the focus order (what gets focus on open, where focus returns on close), the states the component can be in (and how each is announced), the motion rules (honoring prefers-reduced-motion), and the dark-mode coverage (which tokens the designer forgot to spec for dark).

Output is formatted for a developer to implement against — specific, unambiguous, concrete. Not "the dropdown should be accessible" but "the dropdown is a WAI-ARIA combobox pattern: role=combobox on the trigger, role=listbox on the options, arrow keys move between options, Enter selects, Escape closes and returns focus to the trigger."

Pair with The Design Systems Zealot for discussion, The Design Systems Zealot, ARIA Label Rewriter prompt for accessible names on specific elements, Vestibular-Friendly Motion Pass prompt for motion review, and WCAG Reference MCP for the authoritative source.

Who this is for: designers handing off to devs, tech leads reviewing specs before sprint planning, and <span class="whitespace-nowrap">a-gnt</span> folks who want accessibility to live in the design phase instead of bolted on in QA. Not a replacement for designer-developer conversation — a way to make the conversation sharper.

Don't lose this

Three weeks from now, you'll want The Design Spec Translator again. Will you remember where to find it?

Save it to your library and the next time you need The Design Spec Translator, it’s one tap away — from any AI app you use. Group it into a bench with the rest of the team for that kind of task and you can pull the whole stack at once.

⚡ Pro tip for geeks: add a-gnt 🤵🏻‍♂️ as a custom connector in Claude or a custom GPT in ChatGPT — one click and your library is right there in the chat. Or, if you’re in an editor, install the a-gnt MCP server and say “use my [bench name]” in Claude Code, Cursor, VS Code, or Windsurf.

🤵🏻‍♂️

a-gnt's Take

Our honest review

Think of this as teaching your AI a new trick. Once you add it, turns a designer's figma spec into an accessibility-first implementation note for devs — no extra apps or complicated setup needed. It's verified by the creator and completely free. This one just landed in the catalog — worth trying while it's fresh.

Tips for getting started

1

Save this as a .md file in your project folder, or paste it into your CLAUDE.md file. Your AI will automatically use it whenever the skill is relevant.

Soul File

---
name: Design Spec Translator
description: Takes a design spec and produces an accessibility-first implementation note with roles, focus, keys, states, motion, and dark mode.
when_to_use: A designer is handing a spec to a dev and wants the accessibility layer explicit instead of inferred.
---

# Design Spec Translator

## What this skill does
Reads a design spec (Figma description, annotated screenshot, design doc) and produces a developer-facing note that covers the six things specs usually miss: ARIA roles, focus order, keyboard handlers, state announcements, motion preferences, and dark mode token coverage. The result is unambiguous and copy-pasteable into a Jira ticket.

## When to load this skill
Load when the user says: "turn this spec into dev-ready notes", "accessibility handoff for this design", "what does the dev need to know to build this accessibly", "Figma spec review", or pastes a design and asks for implementation guidance.

## The procedure

### Step 1 — Identify every interactive and semantic element
Read the spec and list every element that is either interactive (button, link, input, menu, dialog, tab, accordion, slider) or semantically meaningful (heading, landmark, list, table, figure). Visual decoration doesn't count. For each, name what the designer probably intends it to be, even if the spec doesn't say. A "card" with an onClick is a button (or a link, depending on where it goes). A "chip that can be dismissed" is a button inside a list item. Getting this right is the whole game — every later step depends on knowing what kind of thing this actually is.

### Step 2 — Assign roles and native elements
For each element, prefer a native HTML element. `<button>` beats `role="button"` every time; `<a href>` beats `role="link"`; `<dialog>` or `<section role="dialog">` beats a `<div>` pretending. Only reach for ARIA when the native element can't carry the pattern — custom comboboxes, tree views, tabs, listboxes, menus. When ARIA is needed, name the full pattern from WAI-ARIA Authoring Practices: not just `role="combobox"` but "combobox with inline listbox per APG combobox pattern".

Call out any element where the designer's intent suggests ARIA that's actually hurting accessibility. `role="button"` on a `<a>` (conflict), `aria-hidden="true"` on a focusable element (trap), `role="presentation"` on a landmark (silence).

### Step 3 — Write the focus model
For each interactive component, write the focus model: what gets focus when the component opens, where focus goes when the component closes, what focusable elements are inside, in what order, and whether focus is trapped. For dialogs and modals: focus moves to the first focusable element or the dialog itself on open, traps inside until dismissed, returns to the trigger on close. For menus and dropdowns: focus moves to the first item on open, returns to the trigger on close (Escape) or to the page content on selection (Enter). For non-dismissable components: no focus movement on render.

Also write the page-level focus order: if the spec has multiple components, in what order do they receive Tab? If the visual order and DOM order diverge (CSS grid, flex-reverse), flag it — visual order should win for keyboard users.

### Step 4 — Write the keyboard handler table
For every interactive component, name the keys:
- **Buttons / links:** Enter and Space activate.
- **Checkboxes / radios:** Space toggles; arrow keys move within a radio group.
- **Dialogs:** Escape closes.
- **Menus / listboxes:** Arrow keys move, Enter selects, Escape closes, Home/End first/last, typeahead if the list is long.
- **Sliders:** Arrow keys fine, Page Up/Down coarse, Home/End min/max.
- **Tabs:** Arrow keys move between tabs, Tab moves to panel content.
- **Accordions:** Enter/Space on header, optionally arrow keys between headers.
- **Tree views:** Arrow keys per tree pattern (horizontal expands, vertical moves).

Write the expected keys as a table per component. Developers implement what they see, and "implement keyboard accessibility" is not something they can see.

### Step 5 — Write the state announcements and motion rules
For each component with state (loading, error, success, selected, expanded, disabled), name how the state is announced. Examples: a button with a loading spinner needs `aria-busy="true"` or a live region; a form error needs `aria-invalid` + `aria-describedby`; an expanded accordion needs `aria-expanded="true"` on the header; a selected tab needs `aria-selected="true"`. If the spec has a toast, name whether it's `role="status"` (polite) or `role="alert"` (assertive) — polite for most things, assertive only for errors that interrupt.

For motion: every animation, transition, and auto-playing element needs a `prefers-reduced-motion: reduce` alternative. Specify what the alternative is: no animation (instant), cross-fade only, or reduced duration. Vestibular-disorder users experience animation as vertigo; this is non-negotiable. Parallax, large zoom, auto-rotating carousels all need reduced-motion overrides.

### Step 6 — Write the dark mode coverage and close the note
For each component, check the spec for dark-mode coverage. Does the designer provide dark-mode token mappings? If not, flag the gap: "Dark-mode pairing not specified for the card surface. Recommend `color-surface-raised` / `color-text-primary` dark tokens." Never let a spec ship without explicit dark-mode coverage unless the product doesn't support dark mode.

Close the note with a checklist the dev can run after implementation: can you Tab to every control? Do focus rings show? Does Escape close every dismissable component? Does the screen reader announce state changes? Does the motion honor reduced-motion? Does the dark mode work without visual regressions? Hand off to [WCAG Quick Audit](/agents/skill-wcag-quick-audit) after the implementation lands for a triage pass on the code.

## A worked example

**User:** Figma spec for a "Filter by tag" component. Design: a row of "tag chips" at the top of a list. Each chip has text, a color dot, and on hover an X appears. Clicking a chip filters the list. Clicking the X removes that filter. On mobile, tapping opens a bottom sheet with all tags to choose from. Animates in with a 300ms ease-out.

**Claude:** Implementation note for "Filter by tag".

**Elements identified:**
- Row of chips: visually a list, semantically a toolbar or list of toggles.
- Individual chip: a toggle button (applied / not applied).
- "X" on hover: a second, nested button (remove filter).
- Mobile bottom sheet: a dialog.
- The full-tag selector inside the sheet: a list of checkboxes (not a menu).

**Roles and native elements:**
- Row: `<ul role="list">` with each chip as `<li>`. Alternative: `<div role="toolbar" aria-label="Active filters">` if the chips are treated as a toolbar pattern. Recommend list — simpler and matches the user's mental model ("these are the filters I have on").
- Chip: native `<button type="button">` with `aria-pressed="true"` when active. The "toggle" pattern (pressed/unpressed).
- X-on-hover nested button: problem. Buttons cannot nest. Solution: the X is a sibling `<button>` inside the same `<li>`, not inside the chip button. On hover it becomes visible; on focus (keyboard) it is also visible. For keyboard users, the X must be reachable at all times — hover-only is a bug.
- Bottom sheet: `<div role="dialog" aria-modal="true" aria-labelledby="filter-sheet-title">` with an `<h2 id="filter-sheet-title">Filter by tag</h2>` inside. Use `<dialog>` if the framework supports it.
- Checkbox list: `<fieldset>` with `<legend>Tags</legend>`, then `<label><input type="checkbox"> Tag name</label>` for each.

**ARIA warnings:**
- The color dot is decorative. Mark it `aria-hidden="true"`. The tag name is the accessible name.
- Do not put `role="button"` on the chip. Use `<button>`.

**Focus model:**
- Chip row: Tab enters the first chip. Arrow keys do not move between chips (it's a list, not a radio group). Each chip is a separate Tab stop.
- The X button is its own Tab stop immediately after its parent chip. Tab order: chip 1 → X 1 → chip 2 → X 2 ...
- Bottom sheet: on open, focus moves to the first focusable element inside (the first checkbox, or the dialog heading if it's tabindex=-1 and focusable). On close (Escape or Done), focus returns to the button that opened the sheet.
- Focus traps inside the sheet while open.

**Keyboard handlers:**
| Component | Key | Action |
|---|---|---|
| Chip (toggle button) | Space / Enter | Toggles the filter on/off |
| X button | Space / Enter | Removes the filter |
| Bottom sheet | Escape | Closes, returns focus to opener |
| Checkbox list | Space | Toggles checkbox |
| Bottom sheet "Done" button | Enter | Applies and closes |

**State announcements:**
- Chip pressed state: `aria-pressed="true"`. Screen reader will say "Tag: music, toggle button, pressed."
- Filter removal: when X is clicked, the chip and X should disappear and focus should move to the next chip (or to the previous one if there are no more after). Do not let focus drop to the body — that's a focus-loss bug.
- Bottom sheet open: `aria-modal="true"`; background content should have `inert` attribute or `aria-hidden="true"` applied to the main content while the sheet is open.
- Filter applied via sheet: the list of results should have a live region announcing "Showing X results" when the filter changes.

**Motion (300ms ease-out slide-in):**
- Wrap in `@media (prefers-reduced-motion: no-preference)`. Under reduced-motion, replace the slide with either (a) instant appearance, or (b) a short cross-fade under 100ms. Do not animate `transform: translateY` under reduced motion — vestibular trigger.

**Dark mode coverage:**
Spec shows light-mode chip colors. Missing:
- Dark-mode chip background (recommend `color-surface-raised` in dark).
- Dark-mode chip text (recommend `color-text-primary` in dark).
- The decorative color dot: verify the brand tags still read on a dark background. Some light-mode tag colors will disappear — provide a dark-mode mapping per tag or desaturate them.
- Bottom sheet scrim: in dark mode, a darker-than-background scrim is invisible. Use `color-surface-overlay` or a translucent black layered on top.

**Implementation checklist:**
- [ ] Every chip reachable with Tab, including the X.
- [ ] X button visible on hover and on focus (not hover alone).
- [ ] `aria-pressed` toggles correctly.
- [ ] Bottom sheet has `aria-modal`, traps focus, returns focus on close.
- [ ] Escape closes the sheet.
- [ ] Focus moves to the first checkbox on open, or to a named heading.
- [ ] Live region announces result count after filter changes.
- [ ] `prefers-reduced-motion` overrides the slide-in.
- [ ] Dark mode tokens for chips, text, scrim, and tag dots.

**User:** What if we use a tag with a light yellow that fails contrast in dark mode?

**Claude:** Two options. Either (a) use the dark-mode-specific tag mapping to swap light yellow for a darker gold, keeping the tag identity but passing contrast; or (b) drop the color dot as the semantic carrier entirely and rely on the tag name. Option (b) is what the screen-reader experience already has — the dot is decorative, the name is load-bearing. If the visual dot is purely identity, it's okay for it to be slightly lower contrast as long as the name passes. If the dot is supposed to carry meaning independently (e.g., red = urgent), then it must pass 3:1 as a non-text UI element and you need the dark-mode mapping.

## What this skill will NOT do
- Will NOT infer a spec the designer didn't provide. If the sheet's dismiss behavior isn't specified, Claude asks rather than guesses.
- Will NOT recommend ARIA where a native element works. Native first, ARIA second.
- Will NOT skip dark mode coverage for products that support dark mode. A spec without dark-mode tokens gets flagged.
- Will NOT skip motion alternatives. `prefers-reduced-motion` is non-negotiable for any animation in the spec.
- Will NOT replace designer-developer conversation. It structures the conversation.

What's New

Version 1.0.03 days ago

Initial release

Ratings & Reviews

0.0

out of 5

0 ratings

No reviews yet. Be the first to share your experience.

People Who Use This