How shadcn/ui maps to Figma: variables, styles, and structure

Most shadcn/ui Figma kits are pictures of components. This is a guide to what it takes for a Figma file to genuinely map to shadcn/ui code: shared names, shared tokens, styles as native variable modes, and why that structure is what makes AI design-to-code work.
The problem with "shadcn in Figma"
Search Figma Community for shadcn and you will find plenty of kits. Most of them are static recreations: someone looked at the rendered components and redrew them. They look right on day one, then drift. The layer names mean nothing to a developer, the colors are hardcoded fills, and when shadcn/ui updates, the kit doesn't.
A kit that actually maps to code has to be built the other way around: start from the code, and make every structural decision in Figma answer to it. This post explains what that means in practice, using how we built the shadcncraft kit as the working example.
One name on both sides
shadcn/ui components mark their internal parts with a data-slot attribute. A card has card, card-header, card-title, card-content, card-footer. That attribute is the component's public anatomy: it's how the CSS targets parts and how developers reason about structure.
In the shadcncraft kit, the Figma layer name is the data-slot name. Not inspired by it, not similar to it: the same string.
This is the single decision most kits skip, and it's the one that matters most. When a designer hands over a frame, the developer sees the exact names that exist in the codebase. And when an AI tool reads the file through the Figma MCP, it doesn't have to guess what "Frame 427" is. It reads card-header and matches it to the registry component. This is the difference between generated code that uses your actual components and generated code that approximates them.
Base, style, theme: three words that get conflated
Before the variable structure makes sense, three terms need separating, because most kits (and plenty of buyers) blur them:
- A base is the underlying component library your code builds on. shadcn/ui supports two: Radix UI and Base UI.
- A style is a complete visual system: radius, typography, spacing, icon set, and per-component tokens, not just colors.
- A theme is a color palette applied within a style. Themes load from tweakcn through the plugin, matching every tweakcn property.
These are three independent axes. You can run the Mira style on Base UI with your own brand theme. The whole point of the variable structure below is keeping them independent.
Styles as variable modes
shadcn/ui ships eight official styles, and all eight are native variable modes in the kit: Vega (clean, neutral, and familiar), Nova (reduced padding and margins), Maia (rounded, with generous spacing), Lyra (boxy and sharp, for mono fonts), Mira (made for compact interfaces), Luma (fluid, luminous, and soft), Sera (editorial and typographic), and Rhea (like Luma, but compact).
This is worth pausing on, because it's the part that isn't obvious until you try to build it. Styles differ in radius, spacing, typography, icon treatment, and small structural details. Representing that in Figma without variable modes means eight parallel component sets, which no one would maintain honestly.
Instead, every style-dependent value resolves through a style collection with one mode per style. Switch the mode on a frame and the entire page changes style: components stay attached, overrides survive, nothing is detached or swapped.
The eight official styles aren't the ceiling either. The shadcncraft Figma plugin can author a completely new style (your base color, accent, fonts, icon library, radius) as another mode in the same collection. Your brand becomes a first-class style sitting alongside the official eight.
Variables, not fills
shadcn/ui themes are CSS custom properties: --background, --foreground, --primary, --radius, and the rest. Every color, radius, and spacing decision in the kit is a Figma variable that corresponds to one of these tokens, aligned with the Tailwind token layer underneath.
Nothing in a component is a raw hex value. That has three consequences:
- Light and dark are modes, not duplicate components. The color collection has a light mode and a dark mode. Switching a page is one toggle, and every component follows, because they all resolve through the same variables.
- Themes are data. A brand theme is a set of variable values, which is why a theme built in shadcncraft Create or tweakcn can be applied to the Figma file by the plugin as a new mode, rather than by restyling components.
- The design file and
globals.cssdescribe the same thing. A Figma variable and a CSS custom property with the same token name are two views of one value. That's what makes a round trip possible at all.
Two component bases, one kit
shadcn/ui supports two component bases, Radix and Base UI, and shadcncraft supports both. shadcncraft shipped Base UI support in April 2026, before shadcn/ui made it the default that July.
You don't need a different version of the kit for Radix and Base UI. The anatomy in Figma comes from the data-slot structure, which is the same across bases, so base choice stays a code decision. Combined with the styles, that's 2 bases across 8 styles: 16 combinations from one file.
Icons as a switchable axis
Five icon libraries are included: Lucide, Tabler, Hugeicons, Phosphor, and Remix. Icon choice is part of a style, and switching libraries is supported in both the Figma kit and the React side, so an icon decision doesn't fork your design file either.
Component anatomy: states and variants match props
Each kit component is built so its Figma properties mirror the React prop surface. Variants map to variant props, booleans map to optional parts, and interactive states (hover, focus, disabled, error) exist as real variants rather than as separate mockups.
The point isn't completeness for its own sake. It's that a designer's choices in the properties panel are expressible in code without translation. If Figma offers it, the component supports it.
The round trip
Put together, the structure above enables a loop no static kit can do. The Figma plugin is the engine, and it moves themes in both directions:
In:
- Build or pick a theme in shadcncraft Create or the official shadcn/ui Create page. Every style has a matching preset code; paste it into the plugin and the style is rebuilt in Figma as a native mode.
- Import from tweakcn: presets, a custom URL, or your saved themes.
- Or paste an existing shadcn/ui
globals.cssand the plugin parses it onto Figma variables as a new mode.
Out:
- Export production-ready
globals.cssfrom the current variable values: Tailwind v4, oklch, with light and dark included. - Or use the import variables agent skill from your AI editor, which reads the Figma variables and writes them into your project's
globals.css, mapped to the shadcn token names. - On the Pro Figma + React bundle, the plugin also generates React code from selected frames and the exact shadcn CLI command for any Pro block.
Because the same preset code works on both sides, design and code can't quietly drift apart. Figma isn't a picture of the theme. It's a place the theme passes through, editable in both directions, with the token names as the contract.
Why this structure is what makes AI work
Everything above predates AI tooling as a discipline: it's just design system hygiene. But it turns out to be exactly what AI design-to-code needs.
The Figma MCP lets tools like Claude Code read a file's structure, not a screenshot: layers, variables, component instances. What the AI can do with that depends entirely on whether the structure means anything. In a kit where the layer name is the data-slot, the variables are the shadcn tokens, and the components mirror the registry, the AI's job collapses from "reinvent this design in React" to "identify these known components and compose them." The first produces a lookalike. The second produces your codebase.
The same logic extends past Figma. The hosted Storybook documents every component, variant, and state in a form AI tools can read, and the registry works with the official shadcn MCP server out of the box, so an agent can go from reading the design to installing the matching component in one workflow.
That's the honest reason structure matters. Naming conventions and variable discipline used to be an internal quality bar. Now they're the interface.
Where the free kit fits
The free shadcncraft kit uses the same architecture: same data-slot layer naming, same variable structure, same light and dark modes. If you want to check any claim in this post, open it and look at the layer names and the variable collections. The structure is the product.
Related reading: From Figma to production React, with AI in the loop for the workflow this structure enables, and the step-by-step tutorial if you want to follow along and build a page with it.


