Design Systems Hot Takes

Avoiding tokens

8 min read
2/24/20254 weeks ago

The design systems community was buzzing a few days ago with the announcement of version 2 of the Salesforce Lightning Design System (SLDS). I shared the link to the new documentation on LinkedIn and the engagement has been signifigant.

As someone who has visited dozens of design system documentation sites, there’s certain things I tend to look for when perusing the content. One of those things is how the team handles design tokens. Design tokens are a fundamental feature of what we do, because this unlocks the ability to update the presentation of an experience with less friction. In fact, the term design tokens originated from SLDS many years ago.

That’s why it was so surprising to not find a page dedicated to design tokens in the new version. The term design tokens is mostly absent from the site, except for this quote found on the front page.

SLDS 2 prioritizes CSS custom properties as the visual language and decreases the usage of design tokens.

SLDS 2

Ryan Reynolds meme asking "But why?"

I aimed to find out.

The problem they’re solving

Conversations sparked at the LinkedIn post as well as within the Design Systems Slack where I first saw the link. Alan Weibel, UX Architect at Salesforce, was responding in both places. In all of the discussion, his response to Brad Frost made things more clear.

…I think it depends on how you define design tokens.

If the definition is design tokens are variables (tokens) for design system values, then yes, styling hooks are the same and come with a name-value pair.

If that definition comes with expectations of the specifications in W3C drafts or common implementations of design tokens, then it is not the same. They’re a completely different format that is web first, non-web second.

Alan Weibel, Salesforce UX Architect

This highlighted the issue. The team at Salesforce has considered the use of the word “design tokens” to strictly mean the artifacts coming from the DTCG work. Meanwhile, the community has more commonly considered design tokens to simply be the name-value pairing for design purposes. In other words, at Salesforce “design tokens” equals DTCG specification while outside of Salesforce “design tokens” equals name-value pairings.

So they’ve decided to explicitly distance themselves from the evolving specification but that still doesn’t answer the question of “why?” Here’s another quote from Alan, this time from the Design Systems Slack:

Design tokens are very helpful for a lot of teams. They just aren’t super helpful for Salesforce. It was an extra step to create tokens to be used across multiple frameworks when 99% of Salesforce is on a single platform—the web. Even our native mobile apps use webviews inside of the native wrapper.

We ended up using a web standard, CSS custom properties, as the name/value pair instead of design tokens. These style hooks are a lot easier to manage in both code and tooling. If folks need this CSS for a non-web application, then they can use the THEO tool.

In the end, people still get name/value pairs for all the frameworks but it’s less complex and easier to manage for our platform

Alan Weibel, Salesforce UX Architect

There’s a few notes that I take away from this:

How to fix this

The community had a very similar response to Figma’s variables. When the new feature was announced at Config in 2023, the slide showed the word “design tokens” crossed out. Certainly meant to cause a stir amongst the crowd before announcing variables which work very similar in concept. The team made a conscious decision to not name them design tokens but why? Jacob Miller answers that question in the Design Systems Slack:

…If we tailor-made a solution for design tokens, we’d end up with disparate systems for a bunch of other features that have similar requirements, such as translation strings or conditional prototyping logic.

Rather than do that, we wanted two things: A more unified experience, and more alignment with code. In the same way that you can use css variables to implement design tokens, we wanted that with Figma as well.

Jacob Miller, Figma Product Manager

I wrote about why they were different when variables were first released, along with other design token metadata options at the time.

The difference between Salesforce and Figma is that Figma has documentation which speaks about design tokens and how to implement them within their ecosystem. This makes it easier for folks expecting design tokens to be supported and how to transition those folks into the specific changes within Figma to do similar things.

This is where the decision for the public documentation of the SLDS breaks down. The lack of design tokens or a path for transitioning makes it hard for folks expecting to see the concept. SLDS does have name-value pairs in a similar way to how most of us think of design tokens, they’ve just renamed the concept to Styling Hooks. This is the same as naming your carousel component “Fred”. It might work for your internal team, but cause friction for anyone coming at it for the first time, externally or internally.

I’d recommend that the SLDS team explain in their public documentation how folks looking for design tokens can transition to styling hooks. At best, define “design tokens” more generally as the community currently does or make mention in their blog post that the DTCG was too complex for their needs at this time.

A form of protest

Ultimately, I agree with Salesforce’s decision to avoid the DTCG specification at this time. I’m a highly critical of the current direction. It is my opinion that it is scope-creeping into territories that will make it difficult for it to ever be finished.

For example, the DTCG specification originally defined a color in this way:

{
    "colors": {
        "color-red-500": {
            "$type": "color",
            "$value": "rgba(180, 216, 167, .75)",
        }
    }
}

In the example, the $value is a string. The newer specification is in the process of defining color in this way:

{
    "Acid green": {
        "$type": "color",
        "$value": {
            "$hex": "#00ff66",
            "$colorSpace": {
                "name": "srgb",
                "$components": [180, 216, 167],
                "$alpha": 0.75
            }
        }
    }
}

Among other critisms I have, seeing color defined in this way highlights why Salesforce finds “design tokens” too complicated for their customers. Defining all of the individual parts of a color in a structured object is tedious. It is clear that the community group is less focused on making the file human-manageable at this point and expecting tools to help with the translation. I’m afraid this begins vendor lock-in where you might only be able to edit design tokens from tools. Salesforce Styling Hooks largely avoids the tooling needed to take the DTCG specification into their primary format for the web.

I’ve spoken to Kaelig Deloumeau-Prigent, one of the co-chairs for the DTCG about the direction to this more complex object. The main reason seems to be the difficulty in parsing strings. His example explains that the CSS rgb() color function is an example of the complexity because it takes several different kinds of syntax which any consuming application would need to support. Standarizing the format for systems to injest makes it easier. I contest that this makes it easier for the machines, not for the humans authoring tokens.

I am biased in this area as the creator of Token Operations. While folks could argue that the operations themselves are less accessible for human maintainers, the benefit is that those operations are for the machines but repeatable and sharable. The intention is for a single complex operation to be tucked away from human authors using those operations.

I think a compromise in this area would be best. Where string concatenation could be added into the specification. Such that you could separate parts of the value meant to be concatenated for different platforms, but make it easier to author for humans. Based on my examples in the DTCG issue, string concatenation would solve much of the problems that Token Operations would handle otherwise. This would allow for the original simplified construction while allowing for more complicated multi-platform values to exist. This would also finish the specification much faster by avoiding all of the complexities that might come from every individual $type. Admittedly, this doesn’t solve for a zero-tooling ecosystem that Salesforce might have targetted, but I believe it would make it more accessible to those with minimal tooling.

Being intentional

Over the years, I’ve avoided the word “semantic token” to describe the middle tier due to my strict definition in favor of the word “intent”. I continue to refer to this as a type of design token to keep the concept connected. Where I work today, the word “design token” is rarely used in favor of “intents” which also delivers that strict definition. Where variables could be named and assigned anything, the criteria for similar as “intent” is more systematic and helps maintain a consistent construction and presentation as a result. No one asks “where are design tokens?” because they are design tokens.

It’s ok for design systems to be different, right? 😉

Defending Tailwind Relearning line height