Figma v3 docsView v2 docs

Figma to React mapping

How shadcncraft components in Figma map to their React implementation. A small set of conventions covers every component, so you do not need to memorise them one by one.
PreviousNext

The shadcncraft Figma kit and the React registry are designed to mirror each other. Once you understand the small set of conventions below, you can predict how any component in the kit maps to its React code, including new ones we add later.

This page is convention-first by design. We do not document every component one by one, because that would go out of date the moment we ship a new one. Instead, learn the rules, then read the React source for any component as the source of truth.

The four conventions

1. Component name

The Figma component name matches the React export name.

Figma componentReact exportImport path
CardCard@/components/ui/card
ButtonButton@/components/ui/button
DialogDialog@/components/ui/dialog

If you see a component in Figma called Tooltip, the corresponding React component is Tooltip from @/components/ui/tooltip.

2. Slots are subcomponents, anchored by data-slot

Every React component in shadcn/ui carries a data-slot attribute. The slot name is the bridge between Figma layers and React subcomponents.

For a Figma layer called card-header, the matching React subcomponent is the one rendered with data-slot="card-header", which is exported as CardHeader.

The rule:

Figma layer namedata-slot value → React subcomponent (PascalCase of the slot name)

This works for every component in the system. If you can find the data-slot attribute in the React file, you have the matching Figma layer name and the matching React export.

3. Variant properties are React props

Figma variant properties on a component (for example variant, size, state) map directly to React props of the same name. The allowed values match the variants block in the component's CVA definition.

To find the full list for any component, look at the cva(...) call near the top of the React file. The keys under variants: are the prop names, and the keys under each are the allowed values.

4. States are behavioural, not structural

State variants in Figma (hover, focus, active, disabled, open, etc.) exist so designers can show what the component looks like in each state. They do not become React props. In code, the same look is produced automatically by Tailwind state variants (hover:, focus-visible:, data-[state=open]:, etc.) inside the component itself.

When designing, use Figma state variants to communicate intent. When implementing, do not look for a state prop, the component handles it.


Worked examples

Card — pure composition

Card is the clearest example of the slot convention because it has no variants or state, just slots.

In Figma you compose a card using its named layers. In React you compose it using the matching subcomponents.

import {
  Card,
  CardHeader,
  CardTitle,
  CardDescription,
  CardAction,
  CardContent,
  CardFooter,
} from "@/components/ui/card"
 
<Card>
  <CardHeader>
    <CardTitle>Plan</CardTitle>
    <CardDescription>You're on the Pro plan.</CardDescription>
    <CardAction>
      <Button variant="outline" size="sm">Change</Button>
    </CardAction>
  </CardHeader>
  <CardContent>Renews on July 12.</CardContent>
  <CardFooter>Manage billing in settings.</CardFooter>
</Card>
Figma layerReact exportdata-slot
cardCardcard
card-headerCardHeadercard-header
card-titleCardTitlecard-title
card-descriptionCardDescriptioncard-description
card-actionCardActioncard-action
card-contentCardContentcard-content
card-footerCardFootercard-footer

Button — variants and sizes

Button has no slots but does have two variant properties. Both map directly to React props.

import { Button } from "@/components/ui/button"
 
<Button variant="outline" size="lg">Save</Button>

The full list of allowed values comes straight from the CVA definition in button.tsx:

Figma variant propertyReact propAllowed values
variantvariantdefault, destructive, outline, secondary, ghost, link
sizesizedefault, xs, sm, lg, icon, icon-xs, icon-sm, icon-lg

When we add a new variant or size, this list updates in button.tsx automatically and the Figma variant property gains the same value. No mapping doc to update.

Dialog — compound and stateful

Dialog is a compound component. It has slots (trigger, content, header, title, etc.) and it has state (open, closed). The conventions still hold.

import {
  Dialog,
  DialogTrigger,
  DialogContent,
  DialogHeader,
  DialogTitle,
  DialogDescription,
  DialogFooter,
} from "@/components/ui/dialog"
 
<Dialog>
  <DialogTrigger asChild>
    <Button>Open</Button>
  </DialogTrigger>
  <DialogContent>
    <DialogHeader>
      <DialogTitle>Are you sure?</DialogTitle>
      <DialogDescription>This action cannot be undone.</DialogDescription>
    </DialogHeader>
    <DialogFooter>
      <Button variant="outline">Cancel</Button>
      <Button variant="destructive">Delete</Button>
    </DialogFooter>
  </DialogContent>
</Dialog>

The Figma "open" state variant has no equivalent React prop. The component opens because the DialogTrigger was clicked, and the styling for the open state is applied via data-[state=open]:... Tailwind variants inside DialogContent.

Figma layerReact exportdata-slot
dialog-triggerDialogTriggerdialog-trigger
dialog-contentDialogContentdialog-content
dialog-headerDialogHeaderdialog-header
dialog-titleDialogTitledialog-title
dialog-descriptionDialogDescriptiondialog-description
dialog-footerDialogFooterdialog-footer
dialog-closeDialogClosedialog-close

Reading a component as source of truth

The React file for any component is the canonical reference. To answer "what does this Figma component become in React", open the matching file in components/ui/ and look for:

  1. The data-slot="..." attribute on each function block. This gives you the slot name and tells you which React subcomponent matches which Figma layer.
  2. The cva(...) call, if present. The keys under variants: are the allowed Figma variant properties and their values.
  3. Anything wrapped in data-[state=...]:... Tailwind classes. These are state-driven styles, handled automatically.

If you cannot find a Figma layer that matches a data-slot value, or a Figma variant property that matches a CVA variant, that is a kit gap worth filing.

When the convention does not fit

A small number of components legitimately diverge from the convention:

  • Primitives wrapped from Radix (Dialog, Tabs, Popover, etc.) expose extra subcomponents like DialogPortal and DialogOverlay that are rarely composed in Figma. In Figma, designers usually only show the trigger and content. The other subcomponents still exist in React and follow the same data-slot naming, you just rarely need them in a design file.
  • Charts (the Chart component family) take data, not layers, so the Figma version is a static rendering and the React version is data-driven. There is no slot-for-slot mapping.

If you hit something that does not fit, treat it as documentation owed on that specific component rather than a problem with the convention.

SBIOTJ

Join 3,000+ builders shipping with shadcncraft

Design and assemble full pages faster with production-ready blocks built for real products.
  • Production-ready blocks and components
  • Clean React and Tailwind parity
  • Built for SaaS, marketing, and ecommerce teams
Get the design system
Join Now CTA

Real support from the team behind shadcncraft

Get help within 24 hours from the people who build and maintain the system.
Email
Prefer a direct line? Send us a message and we'll get back to you as soon as possible.
Discord
Get quick support, share feedback, or connect with other builders.
Feedback
Got something to say about anything shadcncraft? We'd love to hear it.