Design-to-code
A Figma instance in a mock should map cleanly to a component import in code — the same name, the same prop set, the same visual identity. This page covers the conventions that make the mapping work and the Figma Code Connect setup that automates it.
If you're a designer hand-shaking with engineering, or an engineer reading from a mock, this is the page.
The naming convention
Figma frame name → code component:
Button / Primary / Md → <Button variant="primary" size="md" />
Pill / Green / Default → <Pill tone="green" />
Eyebrow / Mono → <Eyebrow mono />
DisplayHeading / Hero / H2 → <DisplayHeading size="hero" as="h2" />
BoardConsentCard / Default → <BoardConsentCard … />The pattern: <Component> / <Variant> / <Size or State>. Each / is a level in the Figma variant axis. The leftmost token is always the component name; the rest are props in left-to-right precedence.
When a frame doesn't match a component
Three possibilities, in order of likelihood:
- The component exists; the naming drifted. Most common. Open the Figma file and rename the frame to match the canonical component name. The rest of the mapping falls out.
- The frame is a one-off composition. Pair existing components rather than build a new one. Use a recipe page as the model.
- It's a genuinely new component. Propose it via Governance — the bar is "appears in ≥ 3 real screens." One-off needs don't justify a new component.
Code Connect
Code Connect is Figma's automated design-to-code mapping. The Matter Code Connect map lives in figma-code-connect/ at the repo root.
Each canonical component has a .figma.tsx entry that maps the Figma variant axis to React props:
// Button.figma.tsx — the mapping file
import { Button } from "@matter/components";
import figma from "@figma/code-connect";
figma.connect(Button, "https://figma.com/file/…/node-id=42:317", {
props: {
variant: figma.enum("Variant", {
Primary: "primary",
Secondary: "secondary",
Ghost: "ghost",
}),
size: figma.enum("Size", {
Sm: "sm",
Md: "md",
Lg: "lg",
}),
children: figma.string("Label"),
},
example: ({ variant, size, children }) => (
<Button variant={variant} size={size}>{children}</Button>
),
});With Code Connect active in Figma, a designer's selection in the Inspect panel shows the matching JSX directly — no copy-paste, no guessing.
Adding a Code Connect entry
When a new component lands:
- Write the
.figma.tsxentry. One per component; lives infigma-code-connect/. - Run
figma connect publish. This uploads the mapping to Figma. - Verify in Figma. Select the component instance in Figma → Inspect → JSX renders.
The Code Connect skill (figma:figma-code-connect) automates step 1 — feed it a component's MDX and the corresponding Figma URL, and it scaffolds the entry.
The handoff workflow
Designer → engineering, the canonical flow:
- Designer ships a mock. Every component instance uses a canonical variant (matched by frame name).
- Designer annotates the mock. For each instance, the variant maps to the component name. Code Connect surfaces this in the Inspect panel.
- Designer hands off via PR description. The handoff doc includes:
- Link to the Figma frame.
- List of components used (auto-derived from Code Connect when available).
- Link to the matching recipe page (if the screen mirrors one).
- Any new variants / tokens proposed (separate PRs in
@matter/tokensor@matter/componentsfirst).
- Engineering implements. Imports components, reads tokens (no inline hex), composes from documented patterns.
- Engineering verifies parity. Compare the live render to the Figma mock at the canonical breakpoints. Spot the difference; fix the implementation.
If you're proposing a new variant or token as part of the handoff, those land in @matter/tokens or @matter/components first (with the governance proposal), then the consumer migration ships.
Token names in handoff
Engineering reads design specs for token names, not values. The mock should say:
Background: --bg-elev
Border: --border-soft
Text: --fg-mutedNot:
Background: #FFFFFF
Border: #DDDCD8
Text: #5A5A5AThe hex is incidental — it's what --fg-muted happens to resolve to in light theme. Engineering writes var(--fg-muted), and the value adapts to dark theme automatically. If the mock specifies a literal, engineering has to guess the right token; that's drift.
Per-component handoff checklist
Before pushing a mock to engineering, the designer verifies:
- Every component instance uses a canonical variant (matched by frame name).
- Every color is named by token, not by hex.
- Every spacing value is named by token (
--spacing-*), not by px. - Every typography value is named by token (
--text-*), not by font-size declaration. - Any proposed new variant / token has a separate PR open in
@matter/componentsor@matter/tokens. - The mock renders correctly at the canonical viewports: 360, 768, 1024, 1280.
- Dark-theme variant exists in the Figma file (every component should have one).
Per-implementation handoff checklist
Before opening a PR that implements a mock, the engineer verifies:
- Every component imports from
@matter/componentsor@repo/brand— no app-local clones. - Every color reads through
var(--token-name)— no raw hex. - Every spacing reads through
var(--spacing-*)or the spacing token utility. - The layout reflows correctly at the canonical breakpoints.
- The implementation matches the Figma mock at light + dark + forced-colors.
-
bun run --filter design check:driftis green. - No new design-system primitives invented at the consumer layer.
Anti-patterns
apps/app. It will drift; engineering will lose the design intent on the next change.<Component> / <Variant> / <Size> pattern. The mapping falls out automatically.When you hit a mismatch
| Symptom | Likely cause | Fix |
|---|---|---|
| Component looks right but margin is wrong | Container query or Section padding | Read the recipe; the surrounding Section may set vertical rhythm |
| Color is "off" but the token is right | Wrong theme — designer used dark token in light context, or vice versa | Re-test at both themes |
| Variant from Figma doesn't exist in code | Designer used a Figma-only variant | Propose the variant via Governance, or replace with the canonical variant in the mock |
| Implementation works in light, breaks in dark | Hard-coded color or hard-coded surface | Replace literals with var(--token-name) |
| Forced-colors rendering looks broken | Component doesn't handle forced-colors fallback | Verify per the accessibility matrix |
Reference
- Code Connect documentation — Figma's official guide.
- /components — every canonical component, indexed by name.
- /foundations/color — token naming conventions.
- /governance — proposal workflow for new components and tokens.
- /recipes — full-screen layouts paired with
apps/app/source.
Changelog
What's landed in each release of @matter/tokens, @matter/components, @repo/brand, and the design site. Derived from git history at build time.
Governance
How tokens and components become part of the system — proposal templates, review cadence, deprecation policy, version-bump rules, escalation paths. Read this before opening a PR that touches a token, component, or pattern.