Skip to main content

How to Extract CSS Variables and Custom Properties From a Stylesheet

Pull every --custom-property out of a stylesheet or component file, dedupe the list, and audit which design tokens your CSS actually defines and uses.

Published By Li Lei
#css #design-tokens #custom-properties #frontend #developer-tools

How to Extract CSS Variables and Custom Properties From a Stylesheet

A mature design-token system starts clean: --brand-blue, --space-4, --radius-sm. Eighteen months later nobody is sure which tokens are real. Did someone ship --brand-blue-2? Is --space-4 still referenced anywhere, or did a refactor orphan it? Grep helps, but grep dumps raw lines and leaves you to dedupe by eye. What you actually want is a clean, deduplicated list of every custom property the file touches, with the original line numbers kept so you can jump back to the source.

That is the job CSS Variable Extractor does. Paste a stylesheet, a component file, or anything that contains CSS, and it scans the text for the --name pattern, pulls every unique variable out, and hands you back an audit table you can copy, download, or convert.

What the extractor actually pulls out

CSS custom properties show up in two shapes in any real stylesheet. There are declarations, where you assign a value:

:root {
  --brand-blue: #0af;
}

And there are references, where you read it back:

.button {
  background: var(--brand-blue);
}

Both forms share the same --name token. The extractor scans the pasted text for that pattern and pulls out every unique custom-property name it finds, dropping the selectors, the values, and the comments around them. That is the whole trick to auditing a token system: when you can see the full deduplicated set of --names a file declares and references, you can answer the questions that grep can't — which tokens exist, which are duplicated under near-identical names, and which got typed once and never reused.

To be precise about what this tool gives you, straight from its behavior: it extracts the custom-property names, deduplicates them, and produces a review table with line numbers, normalized values, a validity flag, and a reason for anything that fails. You can keep unique rows only or preserve invalid rows for review, sort the normalized output, and switch the export between CSV, JSON, Markdown, SQL IN, TypeScript union, and plain lines. Everything runs in the browser tab — your source CSS is never sent to a server.

A worked example

Here is a small, realistic snippet with the kind of mess that accumulates in a shared stylesheet — repeated declarations, a reference, and a near-duplicate name:

:root {
  --brand-blue: #0af;
  --space-4: 16px;
  --radius-sm: 4px;
}

.card {
  border-radius: var(--radius-sm);
  background: var(--brand-blue);
}

.card--featured {
  --brand-blue-hover: #09e;
  padding: var(--space-4);
}

Paste that in and the extractor reduces it to its unique custom properties:

--brand-blue
--space-4
--radius-sm
--brand-blue-hover

Four unique tokens, even though --brand-blue and --space-4 each appear twice across declarations and var() references. The duplicate occurrences collapse into one row apiece, and --brand-blue-hover surfaces clearly so you can decide whether it belongs in the official palette or is a one-off that should be folded back into --brand-blue. From there, one click turns the list into a TypeScript union for a typed token map, or a CSV with line numbers for a review doc.

Auditing a token system, not just listing names

The line-number column is what turns a name list into an audit. When --radius-sm shows up, you don't just learn that it exists — you learn exactly where, so you can trace whether it's defined once and referenced widely (healthy) or referenced in twenty places and never declared (a bug waiting to render the fallback). Keeping invalid rows visible matters here too: a line that fails extraction is usually a malformed var() call or a property name missing the required double dash, and seeing it flagged with a reason tells you which declaration to clean up instead of silently dropping it.

A typical audit pass looks like this:

  • Paste the compiled stylesheet or the relevant component file.
  • Keep unique rows on, sort the normalized output, and read the full set of --names.
  • Scan for near-duplicates — --brand-blue next to --brand-blue-2 is the smell of a token that forked instead of being reused.
  • Export CSV with line numbers and attach it to the cleanup ticket so the change is reviewable.

From my own cleanup pass

I ran this on a project where the "design system" had quietly grown to three different blues. I exported the whole stylesheet's custom properties to a sorted Markdown list and the problem was obvious in about ten seconds: --brand-blue, --brand-blue-primary, and --color-blue-brand all sitting next to each other, each referenced by a different team's components. No grep session would have lined them up that cleanly, because each lived under a slightly different name in a different file. I copied the Markdown straight into the migration doc, picked the canonical token, and used the line numbers to find every reference that needed rewriting. The part I appreciated most was that the source CSS never left the tab — it was an internal stylesheet, and I didn't have to think twice about pasting it somewhere.

Where it fits with the rest of your workflow

The extractor is the first step; the cleanup usually continues into a few neighboring tools. If you want to enforce that every extracted name is a well-formed custom property, hand the list to the CSS variable list validator. To strip stray whitespace or casing inconsistencies before you compare two stylesheets, run it through the text file cleaner. And once you've settled on the canonical set, the same engine behind the extractor can convert your list into the exact format your build step expects.

A couple of honest caveats. A name passing extraction tells you the token is referenced or declared — not that it resolves to a real value somewhere, so don't treat a clean list as proof that every token has a definition. And text copied out of a rendered page or a chat often carries hidden whitespace, so normalize before you dedupe or the same token can sneak through as two rows.

Wrapping up

CSS custom properties live a double life as declarations and references, which is exactly why a flat grep never gives you a trustworthy picture. Scanning the text for the --name pattern and pulling every unique variable — with line numbers, validity, and a one-click export — turns "I think these are our tokens" into a list you can actually review. Paste a stylesheet, get the real set of --names, and your next token audit takes minutes instead of an afternoon.


Made by Toolora · Updated 2026-06-13