👩🎨
Design System Utils

Design System Utils is a micro framework that standardises your design-system tokens & provides helpful utility functions to access the information. It can be used with styled-components, emotion, glamorous or any other CSS-in-JS framework.
Install
yarn add design-system-utils
npm install --save design-system-utils
Size
$ size-limit
build/cjs.js
Package size: 814 B
Size limit: 1 KB
es/index.js
Package size: 806 B
Size limit: 1 KB
With all dependencies, minified and gzipped
🤓 Table of contents
Usage
First create your design system file, this contains all your design tokens that your app or site will use; things like font-sizes, color palette, spacing etc (kind of like a Sass/Less variables file).
For example you can create a top-level directory named tokens
, theme
or designsystem
, and add an index.js inside, like so:
./tokens
└── index.js
A simple version of a tokens file with Design System Utils:
import DesignSystem from 'design-system-utils'
const designTokens = {...}
export default new DesignSystem(designTokens)
Setup
The "shape" and structure of your design tokens object can actually be anything you want, however, if you want to make use of the shortcut/helper methods like tokens.fontSize|bp|z|color|brand|spacing
etc, there is a particular shape that your data will need to follow, see below:
(🤔 the below code snippet includes some psuedo types for the values that occur in the different parts of the tokens object)
{
type: {
baseFontSize: ''
sizes: {
key: ''
},
},
colors: {
colorPalette: {
colorName: {
base: ''
},
},
brand: {
colorName: ''
}
},
breakpoints: {
key: ''
},
zIndex: {
key: 10
},
spacing: {
scale: []
},
}
Below is an excerpt from the example design-system. See a more complete version in the /example
directory or some that are used in the design-system-utils tests: 1 & 2.
const designTokens = {
type: {
baseFontSize: '20px',
sizes: {
xs: '16px',
s: '20px',
base: '30px',
m: '36px',
l: '42px',
xl: '50px',
xxl: '58px',
},
fontFamily: {
system:
'-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen, Ubuntu, Cantarell, "Fira Sans", "Droid Sans"',
sans: '"Helvetica Neue", Helvetica, Arial, sans-serif',
serif: 'Georgia, "Times New Roman", Times, serif',
mono: 'Menlo, Monaco, "Courier New", monospace',
},
lineHeight: {
headings: 1.1,
},
fontWeight: {
normal: 300,
bold: 'bold',
headings: 'bold',
},
},
}
Initialise the design system framework
import DesignSystem from 'design-system'
const designTokens = {...}
export default new DesignSystem(designTokens)
Accessing the design system data in your app
To access your design system, you just need to import
it to the current file, like so:
import tokens from './tokens'
Here is a very simple component using styled-components and some values from the tokens, you should be able to see how easy it is to pull information from the design system.
import styled from 'styled-component'
import tokens from './tokens'
export const Box = styled.div`
font-family: ${tokens.get('type.fontFamilyBase')};
background-color: ${tokens.brand('primary')};
margin: ${tokens.space(2)} 0;
`
Options
There is only one option that can be passed to your design system class, it relates to font-sizing:
export default new DesignSystem(myDesignSystem)
export default new DesignSystem(myDesignSystem, {
fontSizeUnit: 'rem',
})
Basic API methods
tokens.get()
- Get a token value
The tokens.get()
function can be used to get any value from the design-system. Use object dot notation to find the value you need from your design system object.
tokens.get('lineHeight.headings')
tokens.get('a.really.deeply.nested.value')
tokens.set()
- Set a token value
The tokens.set()
function can be used to set tokens values. This means you can overwrite existing items, or create new items that are specific to your application.
Like the .get()
method, use object dot notation to find the value you need from your design system object.
This method uses dset under the hood, so please read the docs there for more info.
tokens.set('forms.inputBackground', '#fff')
tokens.get('forms.inputBackground')
API helper methods
The helper methods make getting values much more simple.
tokens.fontSize()
or tokens.fs()
- Get font-size values
The tokens.fontSize()
method is a short-hand for the tokens.get()
method. It can be used to get a value from the type.sizes
object.
The type.sizes
object’s values can be formatted in a few ways:
- as a string with any unit of measurement, e.g.
s: '13px'
/ px
, rem
or em
- as a template string using another function to calculate font-sizes, for example a modular-scale, e.g.
${ms(0, modularscale)}px
. Note: this uses an external package, modularscale-js
sizes: {
xs: '16px',
s: '20px',
base: '30px',
m: '36px',
l: '42px',
xl: '50px',
xxl: '58px',
},
tokens.fontSize('xl')
tokens.fs('xl')
tokens.fs('xl', true)
Modular scale
Note: v0.x.x had modular scale functionality built-in, in v1.x.x, this has been removed to reduce file-size for those that don't need a modular scale.
To make use of a modular scale, there are a few things that need to be done:
- install a modular scale converter package, like modularscale-js
- define your modular scale options outside of your design-system object
- add the modular scale values to the
type.sizes
object
const modularscale = {
base: [30],
ratio: 1.5,
}
...
sizes: {
xs: `${ms(-2, modularscale)}px`,
s: `${ms(-1, modularscale)}px`,
}
...
Testing and remembering the values from your modular scale can be tricky, there are two options that can be used, either:
- visit modularscale.com and enter your settings, you can then view all the type sizes on the scale you specified
- or, add the below snippet to your code to print out the values of your scale:
const sizes = tokens.get('type.sizes')
Object.keys(sizes).forEach(item => {
console.log(item, ':', sizes[item])
})
Color palette
There are two possible ways to access color information: the color palette and the brand colors.
The color palette is intended to contain all the colors (and their shades) that your app will use, and the brand palette should contain the specific colors that your brand uses.
Two methods can be used to retrieve the values, these are: tokens.color()
and tokens.brand()
, below is what the data looks like for them:
colors: {
colorPalette: {
bright: {
base: '#F9FAFB',
dark: '#F4F6F8',
darker: '#DFE4E8',
},
dark: {
base: '#212B35',
light: '#454F5B',
lighter: '#637381',
},
},
brand: {
red: '#e82219',
deeporange: '#ff7200',
orange: '#ff9500',
green: '#c4d000',
teal: '#1aa5c8',
navy: '#0052da',
}
},
tokens.color()
- Get color palette values
The tokens.color()
function gets values from the colorPalette
object. It assumes every color has a base
property and other properties for different shades of the same color.
This is a short-hand for the tokens.get()
function.
tokens.color('bright')
tokens.color('bright', 'dark')
tokens.color('background.extra.dark')
tokens.brand()
- Get brand palette values
The tokens.brand()
function gets values from the colors.brand
object.
This is a short-hand for the tokens.get()
function.
tokens.brand('orange')
tokens.brand('pink')
tokens.brand('primary.blue')
tokens.bp()
- Get responsive breakpoint values
The tokens.bp()
method is a short-hand for the tokens.get()
method. It can be used to get a breakpoint from the breakpoints
object.
tokens.bp('m')
tokens.z()
- Get z-index
values
The tokens.z()
method is a short-hand for the tokens.get()
method. It can be used to get a breakpoint from the zIndex
object.
tokens.z('low')
tokens.spacing()
or tokens.space()
- Get spacing values
The tokens.spacing()
method returns a value from your spacing.scale
definition. The spacing data could either be an array, or an object.
- If an array, it takes an
index
(number) for that array e.g. tokens.space(2)
. This variant adds px
to the end of the string, this will be deprecated in v2.0.0. - If an object, it takes a
key
(string) for the item in that object e.g. tokens.space('m')
Array example:
scale: [0, 8, 16, 24, 32, 40]
tokens.spacing(2)
Object example:
scale: {
s: '10rem',
m: '100rem',
l: '1000rem',
}
tokens.spacing('m')
Calculations
The framework currently provides a few calculation functions, multiply
, toPx
and pxTo
:
tokens.multiply()
tokens.multiply(10, 2)
tokens.multiply(tokens.get('spacing.baseline'), 2)
tokens.multiply('spacing.baseline', 2)
pxTo()
Converts px
to rem
or em
import { pxTo } from 'design-system-utils'
pxTo(12, 20, 'rem')
pxTo(12, 20, 'em')
toPx()
Converts rem
or em
value to px
import { toPx } from 'design-system-utils'
toPx('1.875rem', 16)
toPx('1.875em', 16)
parseUnit()
Parses a number and unit string, and returns the unit used
import { parseUnit } from 'design-system-utils'
parseUnit('1.875rem')
parseUnit('18px')
Usage with Typescript
Typescript types and interfaces should be imported as named imports.
See all the type definitions in the types.ts file. Here are all the exported types that can be extended:
{
System,
SystemOptions,
SystemBreakpoints,
SystemZIndex,
SystemFontSizes,
SystemSpacing,
SystemScale,
SystemColorPalette,
SystemBrandPalette,
SystemType,
SystemOptionalKey,
}
Below is an example where a new item (baseline
) is added to the spacing
object.
import DesignSystem, { System, SystemOptions, SystemSpacing } from '../index'
interface MySystemSpacing extends SystemSpacing {
baseline: number
}
interface MySystem extends System {
spacing: MySystemSpacing
}
const Tokens: MySystem = {
...
...
spacing: {
scale: [0, 8, 16, 24, 32, 40],
baseline: 20,
},
}
export default new DesignSystem<MySystem, SystemOptions>(Tokens)
Demo & examples
I created a demo on codesandbox.io, it includes examples of using the design-system utils with emotion, styled-components and glamorous. There is also a basic example here.
Licence
MIT © Zander Martineau