Every component you build in Figma is a collection of decisions. Layer names, variant structures, token references, nesting rules, conditional visibility. You make dozens of these calls per component, often without thinking about them, because the tool makes it feel like visual work.

It is visual work. But those decisions don't stay visual. They end up in code, in documentation, in structured data files that describe how the component actually behaves. And increasingly, in the context window of whatever AI tool your team is pointing at the codebase.

Most designers never see what their components look like after they leave the design tool. I think that's a blind spot we can't afford anymore, because the quality of everything downstream, the code, the generated UI, the documentation, depends on decisions being made upstream by people who often have no visibility into what they're feeding. I wrote about this dynamic in The hidden cost of design system entropy, and it applies here too.

I'm going to take a single component apart and show you what it looks like as structured data. Once you see how your Figma decisions get expressed in a data file, you start making different ones.

The Alert, as you know it

You've probably built an Alert before, or inherited one from a system someone else put together. In Figma, it might have four or five variants covering different appearances (success, warning, critical, informational), a boolean for whether it's dismissible, maybe a slot for an icon.

You know what this component is for. You know a critical alert is semantically different from an informational one, that the dismiss button only shows up in certain contexts, that the icon should change based on appearance. You understand the relationships because you designed them.

None of those relationships are written down in a way that survives the handoff. They live in the Figma file as visual arrangements and in your head as intent. A developer implementing this component is reverse-engineering your decisions from Figma inspection and Slack messages. An AI tool generating UI from your system is working with whatever structure it can parse. Intent doesn't parse.

Component definitions as data are the fix. They take the decisions you've already made and write them down in a format that's portable, versionable, and machine-readable.

Anatomy

A component definition starts with anatomy. What elements exist, what types they are, how they relate to each other.

alert:
  anatomy:
    root:
      type: container
    icon:
      type: icon
    content:
      type: container
    title:
      type: text
      parent: content
    description:
      type: text
      parent: content
    dismissButton:
      type: interactive
      condition: dismissible == true

If you've built this in Figma, you'll recognise these elements. They're your layers. In Figma, the hierarchy is implicit in how you've nested frames. In the data file, it's explicit. Each element has a type, a name, and a defined position in the structure.

The condition on dismissButton is encoding a specific design decision. The dismiss button only exists when dismissible is true. In Figma, you express this by toggling visibility across variant combinations. In data, it's a single line. Anything reading this file, a developer's IDE, a linting script, an AI agent, immediately knows that element is conditional.

Without this data, a developer opens your Figma file, clicks through variant combinations, notices the button appears in some and disappears in others, and hopefully draws the right conclusion. It works, until it doesn't.

Properties

This is where designers make architectural decisions without realising it.

alert:
  props:
    appearance:
      type: enum
      options:
        - success
        - warning
        - critical
        - info
      default: info
    dismissible:
      type: boolean
      default: false
    title:
      type: string
      required: true
    description:
      type: string
      required: false

Each property maps to something you've set up in Figma. appearance is your variant group. dismissible is a boolean property on the component. title and description are text layers with content that changes per instance.

The data captures something Figma can't express well, though. title is required. description is optional. In Figma, both layers exist in every variant, and there's no structural way to signal which ones a consumer must fill in and which ones they can leave empty. In the data file, that constraint is explicit. Anything consuming it can enforce it.

Why variants, not separate components

This decision deserves more attention than it gets.

When you set up an Alert with appearance: success | warning | critical | info, you're making an architectural choice. You're saying these four things are the same component with different visual treatments, governed by the same anatomy and the same behavioural rules.

The alternative is four separate components. SuccessAlert, WarningAlert, CriticalAlert, InfoAlert. Teams do this. It causes problems every time.

Four components means four implementations in code. Each drifts independently. A developer fixes a padding issue in SuccessAlert and doesn't touch the others. Someone adds a prop to CriticalAlert that doesn't exist on InfoAlert. What started as the same component diverges into four slightly different things that nobody maintains confidently.

With variants, you get one component, one API surface. I've written before about treating components like API endpoints, and this is the practical version of that idea.

<Alert appearance="critical" dismissible>
  <AlertTitle>Payment failed</AlertTitle>
  <AlertDescription>Your card was declined.</AlertDescription>
</Alert>

The appearance prop changes colours, icons, and semantic context. The structure stays the same. That's what the data file expresses when it defines appearance as an enum with four options rather than four separate definitions.

When you use variant properties in Figma instead of duplicating the component, you're already making this architectural decision. You're just not recording it anywhere that persists beyond the design file.

Token references

How you reference tokens in the component data matters for everyone consuming the system.

  alert:
  styles:
    root:
      default:
        borderRadius: token(border.radius.md)
        padding: token(spacing.inset.md)
      appearance:
        success:
          backgroundColor: token(color.surface.success)
          borderColor: token(color.border.success)
        warning:
          backgroundColor: token(color.surface.warning)
          borderColor: token(color.border.warning)
        critical:
          backgroundColor: token(color.surface.critical)
          borderColor: token(color.border.critical)
        info:
          backgroundColor: token(color.surface.info)
          borderColor: token(color.border.info)
    icon:
      appearance:
        success:
          color: token(color.icon.success)
        warning:
          color: token(color.icon.warning)
        critical:
          color: token(color.icon.critical)
        info:
          color: token(color.icon.info)

If your token naming follows semantic conventions (and it should), this reads itself. color.surface.success is a surface colour for success contexts. You don't need to track down a hex value to understand what it's doing.

This is where your token architecture and your component definitions connect. Semantic names make the data legible. Tokens named green-100 or cherry-500 turn the same file into a lookup table that requires a human to interpret, which defeats the entire purpose of expressing things as data. I covered the broader implications of this in Your tokens have become infrastructure.

These references map to the same tokens you'd define in DTCG-format files. The W3C Design Tokens Community Group spec reached its first stable version in October 2025, standardising how tokens get expressed as JSON. The component definition references those tokens, the tokens define the values, and the chain from design decision to rendered output stays readable at every step.

The bits Figma can't express

Some of the most important parts of a component definition have no equivalent in Figma.

alert:
  accessibility:
    role: alert
    liveRegion: polite
    appearance:
      critical:
        liveRegion: assertive
  behaviour:
    autoDismiss:
      type: duration
      default: null
      description: "Time in ms before the alert auto-dismisses. Null means it persists."
    onDismiss:
      type: callback
      description: "Function called when the dismiss button is activated."
  constraints:
    invalidCombinations:
      - dismissible: true
        autoDismiss: "> 0"
        note: "If autoDismiss is set, the dismiss button is redundant."

Accessibility roles, ARIA live region behaviour, auto-dismiss timing, callback definitions, invalid variant combinations. Designers should be making these decisions. But Figma has no structured way to express them, so they end up in a separate document, in someone's memory, or they don't get made at all.

The invalidCombinations field is a good example. It encodes something most teams discover through a bug report. If the alert auto-dismisses, a manual dismiss button is redundant and confusing. Written into the data file, that becomes a constraint you can wire into a linter or CI pipeline. Left in someone's head, it's tribal knowledge that walks out the door when they leave.

What changes when you think this way

I'm not suggesting designers need to learn YAML or start committing data files.

Every decision you make in Figma has a structural consequence downstream. Naming a layer dismissButton instead of Frame 47 makes the anatomy extractable. Using variant properties instead of separate components gives you a single API surface. Semantic tokens instead of hard-coded values create references that survive theming and platform changes.

You're probably doing most of that already. The gap is in the things Figma can't express. Accessibility metadata, behavioural configuration, constraint logic. Those decisions need to live somewhere structured, and the component definition file is increasingly where they end up.

There's real tooling forming here. Nathan Curtis's Anova plugin extracts anatomy, props, and variant analysis from Figma components as structured data. The DTCG spec standardises the token layer. Style Dictionary transforms tokens into platform-specific output. The pieces exist. They're not connected in most teams yet, and designers are usually the last to know about any of it.

There's a lot of conversation right now about whether design software matters anymore, whether AI replaces the whole category. I think that misses the point entirely. Whether you're authoring components in Figma, in code, or describing them to an AI assistant, these decisions still need to get made. Someone needs to decide that an Alert has four appearances governed by one prop rather than four separate components. That the dismiss button is conditional. That a critical alert uses an assertive live region while an informational one doesn't. The tool that records those decisions will probably change. The need for someone to think them through won't.

AI actually makes this harder to ignore. When a designer places elements on a canvas, they carry contextual judgement with them, even if they never write it down. When AI generates UI, it has no context beyond what you give it. The component definition is how you give it context. Without that, you get interfaces generated at speed with no guarantee they're coherent, accessible, or consistent with the rest of your product. I explored this idea from a different angle in AI doesn't need your design system to be perfect. It needs it to be honest.

The more you understand about what your decisions look like as data, the better those decisions get. That's true regardless of what tool you're making them in.


Thanks for reading! If you enjoyed this article, subscribing is the best way to keep up with new posts. And if it was useful, passing it on to someone who'd find it relevant is always appreciated.

You can find me on LinkedIn, X, and Bluesky.

Free tool · Murphy Trueman
CTA Image

Is your design system ready for AI? AI agents are already consuming design systems. Find out if yours is structured to be understood by them.

Take the free assessment →
Share this post