figma-component-scaffold
Paste into Claude Code, Claude.ai, the desktop app, or the browser extension — ⌘/Ctrl+V. ✓ Copied. Switch to Claude and paste — ⌘/Ctrl+V.
Figma Component Scaffold
Generate a production-ready, accessible component from a Figma design using the Figma MCP server. Token values stay as references — no hardcoded hex or px values — and every generated component passes an inline WCAG 2.2 AA contrast check before it is written to disk.
Usage
/figma-component-scaffold <figma-url> [options]
Options:
| Flag | Values | Default | Description |
|---|---|---|---|
--adapter |
react, razor, astro, vue, sitecore, optimizely, umbraco |
react |
Output rendering layer |
--tokens |
file path | auto-detect | Path to the project's .tokens.json or tokens/ directory |
--story |
flag | off | Also generate a Storybook story file |
--css-strategy |
modules, tailwind, custom-properties |
modules |
CSS output style (React/Astro only) |
--output |
directory path | ./src/components/ |
Where to write generated files |
Examples:
/figma-component-scaffold https://figma.com/file/abc123/Design-System?node-id=42-88
/figma-component-scaffold --adapter sitecore --tokens ./src/tokens/tokens.json --story
/figma-component-scaffold https://figma.com/file/abc123?node-id=99-12 --adapter umbraco --output ./Views/Components/
Phase 1 — Read Design Context via Figma MCP
Call the Figma MCP tools in sequence. If the MCP is unavailable, note the limitation and proceed with any design spec or screenshot the user provides.
1.1 Get metadata (high-level node map)
get_metadata(node_url: "<figma-url>")
Extract:
- Component name → derive the kebab-case slug and PascalCase class name
- Node type (COMPONENT, FRAME, INSTANCE, COMPONENT_SET for variants)
- Children structure → layout hierarchy
1.2 Get design context (layout + token references)
get_design_context(node_url: "<figma-url>")
This returns a structured React + Tailwind representation. Extract from it:
- Layout model: flex/grid, gap, padding, alignment
- Typography: font family, size, weight, line-height, letter-spacing
- Color references: distinguish design token names (e.g.
color/interactive/primary) from raw hex/RGB values. Raw values without a token name are gaps — flag them. - Spacing values: map to the project token scale if available
- Radius, shadow, border values
1.3 Get variable definitions (token layer)
get_variable_defs(node_url: "<figma-url>")
Extract:
- All Figma Variables referenced by this component
- Variable collections (Light, Dark, Brand variants)
- For each variable: name, resolved value, group path → map to DTCG token path
1.4 Get screenshot (visual reference)
get_screenshot(node_url: "<figma-url>")
Keep as a reference to validate layout fidelity. Check if the screenshot reveals interactive states (hover, focus, active, disabled, error) not captured in the static node tree.
Phase 2 — Analyse Variants and States
If the node is a COMPONENT_SET (multiple variants):
- List all variant properties (e.g.
Size: sm|md|lg,State: default|hover|focus|disabled|error) - Map each variant to the token values that change between states
- Identify which variants map to interactive states — these require ARIA state attributes
Build a variant matrix:
| Variant | Changed tokens | ARIA state |
|---------|----------------|------------|
| State=focus | color/focus/ring | :focus-visible CSS |
| State=disabled | color/interactive/disabled | aria-disabled="true" |
| State=error | color/feedback/error | aria-invalid="true" |
Phase 3 — Token Mapping
Read the project token file. Check for --tokens flag; if not provided, search common locations:
src/tokens/tokens.json
tokens/tokens.json
styles/tokens.json
design-tokens/tokens.json
src/styles/tokens.json
If no token file is found, note the gap and use CSS custom properties with the Figma variable names
as property names (e.g. var(--color-interactive-primary)).
For each design value extracted in Phase 1:
| Figma Variable | DTCG token path | CSS custom property | Raw fallback |
|---|---|---|---|
color/interactive/primary |
color.interactive.primary.$value |
var(--color-interactive-primary) |
#0057B8 |
Flag any raw value with no corresponding token as a token gap — list these in the output summary so the design team can back-fill the Figma Variable.
Phase 4 — Accessibility Pre-Check
Before generating code, validate the token pairs that will be used in this component.
4.1 Contrast Ratios
For every text-on-background pair and icon-on-background pair, compute the contrast ratio using the relative luminance formula (WCAG 1.4.3 / 1.4.11):
L = (R/255, G/255, B/255) → linearise → 0.2126R + 0.7152G + 0.0722B
contrast = (L_lighter + 0.05) / (L_darker + 0.05)
Gates:
- Body text (< 18pt / < 14pt bold): 4.5:1 minimum
- Large text (≥ 18pt / ≥ 14pt bold): 3:1 minimum
- UI components (borders, icons, focus ring): 3:1 minimum (SC 1.4.11)
If a pair fails, output a [CONTRAST FAIL] warning with the calculated ratio and the nearest
compliant token alternative if one exists in the token file.
4.2 Interactive Semantics Inventory
Determine the correct ARIA pattern by the component type:
| Component type | Required semantics |
|---|---|
| Button | <button> or role="button" + tabindex="0" + keyboard handler |
| Link | <a href> — never <div role="link"> without reason |
| Toggle / Switch | role="switch" + aria-checked + keyboard activation |
| Checkbox | <input type="checkbox"> or role="checkbox" + aria-checked |
| Combobox / Select | role="combobox" + aria-expanded + aria-controls |
| Modal / Dialog | role="dialog" + aria-modal="true" + aria-labelledby + focus trap |
| Accordion | role="region" + aria-expanded on trigger + header id relationship |
| Tab list | role="tablist" + role="tab" + aria-selected + arrow-key navigation |
| Card (linked) | Single <a> wrapping or stretch-link pattern — not multiple nested links |
| Alert | role="alert" or role="status" for live region announcements |
4.3 Focus Indicator Check
Every interactive component must have a visible :focus-visible style. If the Figma spec shows
a focus ring token (e.g. color/focus/ring), use it. If not, apply the project default and flag
the missing Figma spec.
Minimum focus indicator (WCAG 2.2 SC 2.4.11): 2 CSS pixels of enclosed perimeter, 3:1 contrast against adjacent background.
Phase 5 — Generate Component Code
Select the output template from reference.md based on --adapter. Apply:
- Structure — semantic HTML element hierarchy from the Figma layout
- Token references — CSS custom properties or token path imports, no raw values
- Variant handling — props/slots for variant properties; map to token and ARIA state changes
- ARIA — roles, states, and properties from Phase 4.2
- Keyboard —
onKeyDown(React) /@keydown(Vue) /addEventListenerfor Space/Enter on custom interactive elements; arrow keys for composite widgets - Focus —
:focus-visiblestyle linked to focus-ring token;tabIndexcorrect for all states - CSS/styling — follow
--css-strategy
5.1 Adapter: React + TypeScript (default)
- Props interface typed with discriminated union for variants
- CSS Modules:
.module.csswith custom property references - Or Tailwind: utility classes with
cn()helper; token values provided viatailwind.configtheme.extend - Export as named export from
index.tsbarrel
5.2 Adapter: Razor / .NET
.cshtmlpartial view with@model <ComponentName>ViewModel- ViewModel class with XML doc comments mapping each property to the Figma spec
- CSS class names follow BEM or the project convention detected from existing files
5.3 Adapter: Astro
.astrofile with typedPropsinterface- Scoped
<style>block using CSS custom properties - Client directive guidance:
client:visiblefor interactive components
5.4 Adapter: Vue
.vueSFC with<script setup lang="ts">- Props defined with
defineProps<PropsType>() - Scoped styles with CSS custom property references
5.5 Adapter: Sitecore
- React/TSX + Sitecore JSS
ComponentPropsinterface useSitecoreContext()hook for personalisation context if variants map to personalisation rules- Rendering parameter type interface for Sitecore Experience Editor controls
SitecoreNextJsPage/sitecorePagePropsFactoryintegration notes
5.6 Adapter: Optimizely
- React/TSX + Optimizely Content Cloud
BlockComponentProps<TContentType>wrapper - Content type mapping: Figma variants → Optimizely property types (
string,ContentArea,Url) - On-page editing compatibility: avoid
position:absolutechildren that break editor overlays
5.7 Adapter: Umbraco
- Razor
.cshtml+@inject IPublishedContentQueryand typed Umbraco model - ModelsBuilder generated type reference or ModelsBuilder-free strongly-typed extension approach
- Block List / Block Grid editor compatibility: avoid layout assumptions about adjacent blocks
Phase 6 — Storybook Story (--story)
If --story is set, generate a <ComponentName>.stories.tsx (or .stories.ts):
- Default story: renders the default variant
- One story per named variant (State, Size, etc.)
- Accessibility: include
parameters.a11yblock pointing at the root element - Docs: auto-generate
argTypesfrom the props interface
Phase 7 — Output Summary
Write a summary block at the end of the session:
## Component Scaffold Summary — <ComponentName>
**Figma source:** <url>
**Adapter:** <adapter>
**Files generated:**
- <path/to/Component.tsx>
- <path/to/Component.module.css>
- <path/to/Component.stories.tsx> (if --story)
**Token coverage:**
- Tokens resolved: N / N
- Token gaps (no Figma Variable): <list raw values>
**Accessibility pre-check:**
- Contrast: PASS / FAIL (list failing pairs)
- ARIA pattern: <pattern used>
- Keyboard model: <Enter/Space|arrow-keys|none>
- Focus indicator: PASS / FLAGGED
**Next steps:**
- Run /component-a11y-gate on the generated files for a full static review
- Back-fill missing Figma Variables for flagged token gaps
- Run /design-system-sync if token file is out of date with Figma Variables
Reference files
reference.md— Component templates per adapter (React, Razor, Astro, Vue, Sitecore, Optimizely, Umbraco)examples.md— Worked examples: Card, Button, Form Field, Navigation, Modal, Tab Listtemplates.md— Storybook story templates, ViewModel class templates, Sitecore/Optimizely/Umbraco model stubs
Technical details
- Plugin
- design-to-code-builder
- Author
- Dakota Smith
- Skill name
figma-component-scaffold- Maturity
- experimental
- Security review
- No security review
- Owners
-
- engineering
- design
- Argument hint
<figma-url-or-selection> [--adapter react|razor|astro|vue|sitecore|optimizely|umbraco] [--tokens <path-to-tokens.json>] [--story]- Allowed tools
-
ReadWriteEditGlobGrepmcp__figma-dev-mode-mcp-server__get_design_contextmcp__figma-dev-mode-mcp-server__get_variable_defsmcp__figma-dev-mode-mcp-server__get_metadatamcp__figma-dev-mode-mcp-server__get_screenshotBash(node *)Bash(npx prettier *)Bash(npx tsc --noEmit *)
- Source
plugins/design-to-code-builder/skills/figma-component-scaffold/SKILL.md
Edit this skill on GitHub — opens GitHub's web editor. No git knowledge needed.