Hey everyone! I'm in the process of creating a white-label design system and have hit a bit of a snag regarding design tokens. We're following a structure that goes from primitives to semantics to components, and that's been working well so far. However, I've started to run into complications when brands have different requirements. For instance, our semantics are fixed, like 'brand.primary', but Brand A prefers red while Brand B wants blue. If I follow this structure strictly, it means that blue would need to exist in the primitives, which then requires the semantics to map to it, before each brand can override that mapping. This process feels like it's getting a bit complicated.
My ultimate goal is to make colors and typography completely configurable through a CMS, but now I'm wondering whether I should fully stick to W3C design tokens or simply store semantic values directly in the CMS, such as 'brandPrimary: "#123311"' or 'fontH1Weight: 700'.
I'm torn because primitives seem too low-level for the CMS, while semantics feel appropriate as the right abstraction. But will I be straying from best practices if I choose to skip the strict token references?
Has anyone out there built a white-label system like this? What keeps things in code versus what goes into the CMS? I'm really eager to hear thoughts from those with experience doing this at scale!
1 Answer
Definitely map those to your primitives. However, it's worth considering why you'd want to expose those through a CMS. Are you letting users change the underlying color palettes? Do you really want them switching from neon to pastels? In my experience, users typically just want to interact with the semantic layer. So start with it mapped to the primitives, and then allow them some flexibility to override with custom values if needed.

In our case, the CMS isn’t for end users, it’s meant for internal brand onboarding. Each white-label brand has its own distinct palette and typography. Do you still think it's crucial to maintain a clear primitive to semantic mapping in this scenario, or could we simplify things by resolving semantics directly from the CMS without having primitives?