Table of Contents
1 | Introduction to Design Tokens
2 | Managing and Exporting Design Tokens With Style Dictionary
3 | Exporting Design Tokens From Figma With Style Dictionary
4 | Consuming Design Tokens From Style Dictionary Across Platform-Specific Applications
5 | Generating Design Token Theme Shades With Style Dictionary
6 | Documenting Design Tokens With Docusaurus
7 | Integrating Design Tokens With Tailwind
8 | Transferring High Fidelity From a Design File to Style Dictionary
9 | Scoring Design Tokens Adoption With OCLIF and PostCSS
10 | Bootstrap UI Components With Design Tokens And Headless UI
11 | Linting Design Tokens With Stylelint
12 | Stitching Styles to a Headless UI Using Design Tokens and Twind
What You’re Getting Into
In the previous article, I wrote about my process to create a CLI that generates a “scorecard” rating an application’s adoption of design tokens.
This tooling is useful to make sure that applications within a company are actually using the design tokens that are available to them.
A scorecard is a nice tool for acute, or short-term, testing. It would work well when applications in a company adopt new design tokens following an initiative.
It can be useful for chronic, long-term testing (i.e. manual testing that a developer and/or QA tester does before releasing new code).
However, catching the implementation of unofficial design tokens during local development is a better experience for the developer and more likely to prevent the release of unofficial design specifications.
Just as an EsLint plugin works well to catch improper syntax before a manual code review, so too, linting to catch the implementation of unofficial design tokens can lighten the load of manual testing.
A tool called Stylelint offers the ability to lint your CSS.
What if there was a Stylelint plugin that could detect the implementation of unofficial design tokens/specs when given the official set of tokens?
In this brief article, I’ll show how I ventured to build such a plugin.
The Process
To start, I read through the developer’s guide on writing Stylelint plugins.
Then, I looked through the source code of existing plugins that I found on the awesome-stylelint repo.
This helped generate the boilerplate code for a Stylelint plugin.
Ultimately, the Stylelint plugin consists of rules that can be enabled by a user.
Each rule is a function that takes in the user’s options for a rule which
they configure. You have to validate these options in the code using a
utils.validateOptions util that the Stylelint package
provides for you. Also, you should document these options in your
documentation.
I wrote the function for an official-specs rule that expects
the user to configure/provide a set of official design tokens/specs:
import scorecard from '@tempera/postcss-scorecard';
import { utils } from 'stylelint';
import { namespace, validateSpecs } from '../utils';
export default {
'official-specs': function rule(specs = {}) {
return (root, result) => {
const validOptions = utils.validateOptions(result, ruleName, {
actual: specs,
// validateSpecs is a function
// that validates that
// the provided specs is a flat
// object consisting of key-value pairs
possible: [validateSpecs]
});
if (!validOptions) {
return null;
}
};
};
Next, I used the @tempera/postscss-scorecard plugin which I created for a “scorecard” reporting tool as an API.
This plugin exposes hooks into the processing of CSS to do something when a valid or invalid specification is found:
const scorecard = require("@tempera/postcss-scorecard");
const specs = require("./tokens");
await postcss()
.use(
scorecard({
onInvalid: (score) => {
// do something when CSS property is not an official spec
},
onValid: (score) => {
// do something when CSS property is an official spec
},
onFinished: () => {
// do something after validation finishes
},
specs, // the official design tokens
})
)
.process(css, { from: undefined });
It also provides a score context which contains the
prop, value, as well as the predicted
nearestValue (the closest official value to the unofficial
value).
Using this as an API in the Stylelint rule, messages can be reported when
a CSS declaration is using an invalid/unofficial value by using the
utils.report method.
The utils.report method expects a rule message that can be
generated using the utils.ruleMessages method.
I exposed a rule message that receives the actual/unofficial spec and the
nearest official spec from the score context.
import scorecard from '@tempera/postcss-scorecard';
import { utils } from 'stylelint';
import { namespace, validateSpecs } from '../utils';
export const ruleName = namespace('official-specs');
export const messages = utils.ruleMessages(ruleName, {
'official-specs': ({ spec, nearestSpec }) => {
const prefix = `An unofficial spec was detected: "${spec}"`;
if (!nearestSpec) {
return prefix;
}
return `${prefix}. The nearest official spec is ${nearestSpec}`;
}
});
export default {
'official-specs': function rule(specs = {}) {
return (root, result) => {
const validOptions = utils.validateOptions(result, ruleName, {
actual: specs,
possible: [validateSpecs]
});
if (!validOptions) {
return null;
}
const { Once } = scorecard({
onInvalid: (score) => {
const spec = score.value;
const nearestSpec = score.nearestValue;
const node = score.context;
utils.report({ message: messages['official-specs']({ spec, nearestSpec }), node, result, ruleName })
},
specs,
});
Once(root);
};
};
Just like that, we can provide linting around the usage of unofficial design specifications in CSS:
🎉 Cool!
Final plugin: https://github.com/michaelmang/tempera/tree/master/packages/stylelint
Conclusion
I hope this experimental plugin helps to highlight the potential to enforce the usage design tokens.
I hope it also helps to stimulate creativity for future tooling to unleash the power and success of adopting design tokens.

