How to Validate CSS Variables: Catch Broken Custom Property Names Fast
Validate CSS variables and custom property names against the real -- prefix and identifier rules, flag broken rows with reasons, and clean a token file.
How to Validate CSS Variables: Catch Broken Custom Property Names Fast
A design-token file looks tidy until you actually try to use it. One line says brand-blue: #1d6fe0 and a reviewer assumes it works, but the browser silently ignores it because it never started with --. Another line is --brand color: #fff, with a space sitting in the middle of the name, so var(--brand color) resolves to nothing. These mistakes do not throw errors. They just quietly fail at runtime, and you find out when a button renders with no background.
The CSS Variable List Validator exists for exactly this: paste a list of custom property names, get a pass/fail report with a reason next to every row, and hand off a file you can trust. Everything runs in your browser tab. Nothing about your tokens is sent to a server.
What a valid CSS custom property name actually is
A CSS custom property name has a narrow, specific shape, and the tool checks against it directly:
- It must begin with two dashes (
--). A name likebrand-bluewith no leading--is not a custom property at all; the parser flags it. - After the
--, the name is built from identifier characters CSS allows. A name that carries a character CSS does not allow in an identifier (a space, for example) is flagged with the reason printed beside that line. - The name must not be empty. A bare
--with nothing after it has no identifier, so it fails. - Custom property names are case-sensitive.
--Brandand--brandare two different variables, and the tool treats them as distinct rows rather than collapsing them.
That is the core of what this tool checks per row: is there a leading --, is there an identifier after it, and does that identifier avoid characters CSS does not allow. Each failing row stays in the output with the exact reason, because the whole point is to surface the broken names, not hide them.
It is worth being honest about scope. Passing validation means the name is well-formed, not that the variable is referenced anywhere, not that the value behind it is a real color, and not that the token is wired into your build. Format-correct is not the same as in-use. Treat a green row as "this name is syntactically a CSS custom property," and nothing more.
A worked example: cleaning a token list
Say you inherited a half-migrated token file and pasted these six lines:
--brand-primary
--brand-blue
brand-secondary
--brand color
--
--Accent-2
Run them through the validator and you get a per-row report. In CSV form it reads like this:
value,normalized,line,valid,reason
--brand-primary,--brand-primary,1,true,OK
--brand-blue,--brand-blue,2,true,OK
brand-secondary,brand-secondary,3,false,missing leading --
--brand color,--brand color,4,false,illegal character in identifier
--,--,5,false,empty identifier after --
--Accent-2,--Accent-2,6,true,OK
Four names are well-formed: --brand-primary, --brand-blue, and --Accent-2 all start with -- and use legal identifier characters. The interesting one is --Accent-2 — it passes, and it stays distinct from any --accent-2 you might also have, because names are case-sensitive.
The three failures each carry a reason. brand-secondary never had its --, so it is not a custom property. --brand color has a space, a character CSS does not allow inside the identifier. -- has nothing after the dashes, so there is no identifier to name. You now know precisely which three lines to fix and why, instead of squinting at the diff.
Beyond pass/fail: dedupe, sort, convert
Validation is the headline, but most cleanup jobs need a few more moves, and the tool keeps them in the same tab:
- Keep unique rows only. A merged token file often has the same name pasted twice from two branches. Deduplication collapses exact duplicates while respecting case, so
--brandand--Brandsurvive as two entries. - Preserve invalid rows for review. You can keep the failing rows in the output so a teammate sees what needs fixing, or strip them once they are resolved.
- Sort the normalized output so the final list is stable and diff-friendly.
- Switch formats. Export the clean list as CSV, JSON, Markdown, SQL
IN, a TypeScript union, or plain lines — whichever your next step actually consumes, without hand-adding quotes and commas.
For sensitive profiles such as cards and JWTs, values are masked in the output while you still get the validation signal. For a token list that is not a concern, but it means the same engine is safe to point at a log that happens to contain secrets.
How I use it in a real review
I keep this tab open during design-system PR reviews. When a contributor sends a token batch, I do not read the names by eye anymore — I learned that lesson after approving a file where --space-md had a stray non-breaking space copied in from a spreadsheet, and var(--space-md) quietly resolved to nothing across three components. Now I paste the whole list, scan the reason column, and only the flagged rows get my attention. The two minutes it takes have caught more broken tokens than any amount of careful reading, mostly because hidden whitespace and a missing -- look identical to a human and obvious to a parser.
One habit worth keeping: copied text from a spreadsheet or a web page often carries hidden whitespace, so normalize before you dedupe or import. A name that looks clean can still hide a trailing space that makes it a different string.
Where to go next
If your job is closer to pulling names out of a stylesheet than checking a hand-written list, reach for the CSS Variable Extractor to harvest every --token from a CSS file first, then validate the result here. And if your problem is that the same name shows up in three casings and two spellings, the CSS Variable Normalizer gives you one canonical form before you ship the file.
The workflow that holds up: extract the names, normalize them, validate against the real -- and identifier rules, fix the flagged rows, and export the format your pipeline wants. Every step stays in the browser, so a token file full of internal names never leaves your machine.
Made by Toolora · Updated 2026-06-13