Building a Design System From an Imported Site in Figma

An import gives you layers, not a system. Audit the repeated colors, type sizes and spacing, collapse them into a scale, then build primitive and semantic tokens in Figma.

TUTORIALDESIGNERPublished

An import gives you layers, not a design system. To get from one to the other, you audit the values the page repeats, collapse near-duplicates into a scale, and name what is left as primitive and semantic tokens in Figma. This tutorial assumes you already have the page in Figma and know your way around variables. As of October 2026, expect to do most of this by hand.

The steps below work for a redesign of a site with no design file, a competitor teardown, or a legacy rebuild. The goal is a small system you can actually maintain, not a complete inventory of everything the page happens to contain. Plan on an hour or two for a typical marketing page, and longer for a product UI with many states. The prerequisite is simple: an imported page open in Figma, with fonts resolved, and edit access to the file where the variables will live.

Audit the import before naming anything

Start by cleaning up the import. Delete hidden noise and flatten layers that exist only because of how the page was built. Naming tokens on top of clutter gives you a tidy name for junk.

Then collect what repeats. You want five lists:

  1. Fill and text colors
  2. Font sizes, with weight and line height
  3. Spacing values (padding and gap)
  4. Corner radii
  5. Shadows

Count how often each value appears. A value used once is a one-off, not a token. A value used twelve times is a candidate.

One limit worth stating plainly: the UnHTML product page does not say that CSS custom properties or design tokens from the source page are carried into Figma. Treat the import as raw values and build the variables yourself. Figma's own webpage capture is different, and we cover it near the end.

Collapse near-duplicates into a scale

Real pages are messy. You'll find four grays that differ by a few points of lightness, and padding values like 14px, 15px and 16px side by side. Pick one value per cluster and snap the rest to it.

Keep a working table so the decisions stay visible:

Audited valueTimes usedChosen token value
#6b7280, #6c727f, #6b738131#6b7280
14px, 15px, 16px padding2216px
3px, 4px radius94px

Don't chase every outlier. If a value appears once or twice and does not fit the scale, leave it as a local override. Keep the first pass smaller than the audit suggests. It's easier to defend and easier to extend.

Primitive tokens first, then semantic ones

Figma's guidance on tokens separates tokens into layers, and that split is the backbone of the system.

Primitives define what exists

Primitive tokens list every value in the system, such as each brand color or spacing step. Figma describes them as "for reference only," so you do not apply them directly to designs. Name them by value, for example gray/500 or space/16.

Semantic tokens say how to use it

Semantic tokens carry intent. In Figma's example, surface/brand-contrast points to the primitive pink/400. Because semantic tokens alias primitives, changing the base value updates everything that depends on it. Use full words over abbreviations and keep prefixes consistent, so names stay valid as the system grows.

Component tokens, only when you need them

A component token names where a value applies, in the form button-primary-background-default. Add these when a component needs to diverge from the shared semantic layer. Skip them on the first pass.

Variables for values, styles for composites

Figma variables and styles do different jobs. Most teams use both. Variables support aliasing, multiple modes for theming, scoping, and code syntax. Styles hold composite values, such as several fills or several shadows on one layer.

That has a practical consequence for an imported page. Single values like colors, spacing and radii go into variables. A layered shadow stays a style, and so does a gradient, because variables cannot hold gradients. If you want to see how those two arrive from the page, read about how box-shadow maps to a Figma effect and what happens to CSS gradients.

Mirror the tokens as CSS custom properties

If a developer will implement the system, give them tokens that match. MDN's reference is clear on the rules that matter: custom properties are scoped to the elements they are declared on, they take part in the cascade, and they inherit. Names are case sensitive, so two spellings of the same name are two different properties.

A minimal mirror of the table above looks like this:

:root {
  --gray-500: #6b7280;
  --space-16: 16px;
  --radius-4: 4px;

  --text-secondary: var(--gray-500);
  --card-padding: var(--space-16);
}

The first block is the primitive layer. The second is the semantic layer, written as aliases with var(). The structure matches the Figma collections one to one.

Naming pays off a second time. When you capture a page with Figma's own webpage capture, Figma binds CSS variables to Figma variables in a fixed order: it matches the CSS name to the variable's code syntax first, then to the variable name, then falls back to the best-fitting variable with the most limited scope. Set code syntax on your variables, keep CSS names readable, and capture from a dev server where build tools have not scrambled the names. Color variables with opacity are not bound, so check those by hand.

Check the system against the page

A token set earns its keep only if it can rebuild the page you started from. Pick two or three representative frames from the import and rebind their fills, text colors, padding and corner radius to the new variables, working from the semantic layer. Then compare the result to the original.

Expect small shifts. Snapping 14px and 15px padding to 16px moves things by a pixel or two, and that is the trade you chose when you collapsed the scale. If a shift is large enough to change the layout, the cluster was wrong: split it into two tokens, or keep the outlier as a local override. This is also where you find the values the audit missed, such as a hover color that only exists on one component.

Name the system so others can use it

Write down what each collection is for. A short description on each variable collection is enough: which layer it is (primitive or semantic), whether designers may apply it directly, and who owns changes. Use the scoping options in Figma variables so a spacing variable does not show up in the color picker.

If you also keep the CSS mirror, treat the Figma collections as the source of truth and update the stylesheet when they change. Two sources of truth drift apart fast. Dark mode and other themes are the one place to add a second mode early, because aliasing means only the semantic layer changes between modes.

Components and styles come second

Once tokens exist, reuse is the next step. On Pro, UnHTML turns recurring type into shared text styles and repeated elements into components, as covered in turning a Pro import into components and text styles. Do the tokens first. Components and text styles then have real variables to bind to, instead of stray hex values.

Conclusion

Audit what the page repeats, snap near-duplicates into a scale, and split the result into primitives and semantic tokens. Put single values in variables, keep composites as styles, and mirror the names in CSS so designers and developers share one vocabulary. Start small, and add a token only when a value earns it. The import saves you the rebuild of the page. The system is still your call.

Questions

Does UnHTML turn a site's CSS variables into Figma variables?
The UnHTML product page does not say it carries CSS custom properties or design tokens into Figma, so plan to build the variables yourself from the values you audit. Figma's own webpage capture does bind CSS variables to Figma variables, by code syntax first and variable name second.
Should I use Figma variables or styles?
Both. Variables suit single values such as colors and spacing, and they support aliasing and modes. Styles hold composite values such as multiple shadows, and gradients stay as styles because variables cannot hold them.
How many tokens should the first pass have?
Fewer than the audit suggests. Merge near-duplicates into one scale, then add tokens only when a value repeats.