Tokenizing a design system and components with SCSS
Has anyone here "fully" tokenized a project? I am talking about tokenizing not only the main variables but also component variables. I am using SCSS and a complete tokenization seems like it's going to help me reuse much of my styling and also allow for customization in the future, but I do not have much experience with it so I don't know much about how to do naming and hierarchy, so I am here looking for resources.
6 Replies
Hi, yes, we have a design system with 80+ components, 2000 design tokens, 5 color themes , each including a dark theme - everything is fully tokenized. I also use SCSS. Exporting variables from Figma into any format — CSS, SCSS, StyleX variables, etc. — is very simple, and it can then directly send a merge request to your repository. Any change made in Figma is reflected in the code within a few seconds.
When it comes to structure, you need to define core tokens first — for example, --measure2, --measure4, etc. The number represents pixels, and it’s easy to read. Labels with suffixes like sm, xl, xxl, etc. are not very useful — when you need something in between, you can’t fit the size properly. That’s why it’s best to name tokens by their actual values, so everyone can easily understand them.
The units can, of course, be converted to rem, but that’s not essential for understanding the naming convention. It doesn’t really matter which unit you choose; it depends on the scenarios you expect your design system to handle.
As for core colors, I recommend naming them like --colorRed500, --colorRed650, etc. That gives us up to 20 shades per color, which is more than enough. I’d suggest choosing 500 or 600 as the main one and deriving others from it. I recommend using the OKLCH color format — it’s great for dealing with contrast issues.
Then we have core fonts, which can be named like --fontFamilyRoboto, --fontWeight500, etc. Core tokens never change — they act as constants.
The second level consists of semantic tokens, which always inherit from core tokens. For example:
--gap8: var(--measure8);
--colorPrimary: var(--colorRed500);
--colorPrimaryHover: var(--colorRed600);
--fontFamilyPrimary: var(--fontFamilyPrometo);
These semantic tokens cover base scenarios and can be directly linked to components and the layout system.
The last level is component-specific tokens, for example:
--buttonPaddingInline: var(--spacing8);
--buttonBgColor: var(--colorPrimary);
Component-specific tokens are optional — a complete design system can be built purely on semantics. It depends on what your plans are for the design system.
If you have multiple themes and components behave differently across them — for example, in theme A a button and accordion panel both have an 8px border radius, but in theme B the button has 4px and the accordion panel 16px — then logically you can’t use semantic tokens, and that’s where component-specific tokens come in. That’s the main decision rule.
In short, that’s more or less the most important thing regarding token structure.
This is also a good use case for locally scoped custom properties
@depthark, that's very nice. Thanks for the advices
I am starting with my component tokens and so for I have created for each component a file like
_button.token.scss and inside my structure looks like this:
And I use like this:
I still don't how I'll do theming, in the sense of how to create variations for e.g. the button tokens (and the other component tokens too)
(Oh, I am using SCSS variables only)I’m not sure about SCSS, but in CSS, you can have multiple files containing :root variables with design tokens, and use a JS theme provider to load the theme you need at the moment.
Oh, got it. Also, @depthark, I don't want to bother you, but have you felt any performance issues using that many CSS variables?
No, CSS variables can cause performance issues only if you overengineer their usage — meaning if you change their values dynamically or have too many levels of inheritance across components, etc.
Browsers load the variables in :root once during CSS parsing and use them as static references. Their amount has a negligible impact on rendering performance, even if there are several thousand of them — the only thing that increases slightly is the CSSOM memory footprint, which is completely normal.