Appearance
Behavioural Tokens
Why?
Group default, :hover and :active state tokens meaningfully.
The behavioural token encodes through data structure (rather than naming convention) the relationship between tokens used in default, hover and active states.
Hidden in design tokens
Many design systems will have, somewhere in the semantic layer, tokens that look something like this:
Semantic Tokens
Name
Light
Dark
Semantics
Primary
Background
Default
Primitives/Primary/300Primitives/Primary/1100 Hover
Primitives/Primary/400Primitives/Primary/1000 Active
Primitives/Primary/500Primitives/Primary/900Semantics
Secondary
Background
Default
Primitives/Secondary/300Primitives/Secondary/1100 Hover
Primitives/Secondary/400Primitives/Secondary/1000 Active
Primitives/Secondary/500Primitives/Secondary/900There's a clear intent here, expressed through the naming, that a component using a background color of Semantics/Primary/Background/Default should also use a background color of Semantics/Primary/Background/Hover when in hover state (if applicable) and likewise for active state.
However, there's no easy way to apply this to a component that doesn't require the designer to manually select each one.
A development hotch-potch
Similarly, in development, at the worst case you will end up with something like this:
Positive
Negative
css
.widget-positive {
background-color: var(--sentiment-positive-background-default);
color: var(--sentiment-positive-foreground-default);
border-color: var(--sentiment-positive-border-default);
&:hover {
background-color: var(--sentiment-positive-background-hover);
color: var(--sentiment-positive-foreground-hover);
border-color: var(--sentiment-positive-border-hover);
}
&:active {
background-color: var(--sentiment-positive-background-active);
color: var(--sentiment-positive-foreground-active);
border-color: var(--sentiment-positive-border-active);
}
}
.widget-negative {
background-color: var(--sentiment-negative-background-default);
color: var(--sentiment-negative-foreground-default);
border-color: var(--sentiment-negative-border-default);
&:hover {
background-color: var(--sentiment-negative-background-hover);
color: var(--sentiment-negative-foreground-hover);
border-color: var(--sentiment-negative-border-hover);
}
&:active {
background-color: var(--sentiment-negative-background-active);
color: var(--sentiment-negative-foreground-active);
border-color: var(--sentiment-negative-border-active);
}
}html
<div class="widget-positive">Positive</div>
<div class="widget-negative">Negative</div>This is just for one component with two sentiments - when other components need sentimentality, there's nothing here that can be reused.
Torquens
The behavioural token exists to fill this void. Design systems implementations may already have something in place for this:
Positive
Negative
scss
@use "behavioural" as *;
.widget-positive {
@include behavioural(background-color, --sentiment-positive-background);
@include behavioural(color, --sentiment-positive-foreground);
@include behavioural(border-color, --sentiment-positive-border);
}
.widget-negative {
@include behavioural(background-color, --sentiment-negative-background);
@include behavioural(color, --sentiment-negative-foreground);
@include behavioural(border-color, --sentiment-negative-border);
}scss
@mixin behavioural($prop, $color) {
#{$prop}: var(#{$color}-default);
&:hover {
#{$prop}: var(#{$color}-hover);
}
&:active {
#{$prop}: var(#{$color}-active);
}
}html
<div class="widget-positive">Positive</div>
<div class="widget-negative">Negative</div>But the pain here is that this is using a token that doesn't exist in your semantics.
The solution here is to create a new set of tokens that can switch between the different states.
Behavioural Tokens
Name
Default
Hover
Active
Semantics
Primary
Background
Semantics/Primary/Background/DefaultSemantics/Primary/Background/HoverSemantics/Primary/Background/Active Foreground
Semantics/Primary/Foreground/DefaultSemantics/Primary/Foreground/HoverSemantics/Primary/Foreground/Active Border
Semantics/Primary/Border/DefaultSemantics/Primary/Border/HoverSemantics/Primary/Border/ActiveSemantics
Secondary
Background
Semantics/Secondary/Background/DefaultSemantics/Secondary/Background/HoverSemantics/Secondary/Background/Active Foreground
Semantics/Secondary/Foreground/DefaultSemantics/Secondary/Foreground/HoverSemantics/Secondary/Foreground/Active Border
Semantics/Secondary/Border/DefaultSemantics/Secondary/Border/HoverSemantics/Secondary/Border/ActiveNow, consumers can reference Semantics/Primary/Background, and have a mode to switch between states.