Friend, my first design system took 3 years to build. My last just 3 days. Here's what I learned.
First, what is a design system anyway?
A design system is the ideal workflow for UI. A set of core reusable elements and rules that spit out good-looking interfaces without design skill on your part.
You and your designer set the tone once, create the elements, some basic rules, then you work from mockups. Everything you build looks perfect and your designer spends time on UX not fiddly details.
You the engineer can build perfect UI from a napkin sketch.
That's the theory.
Life is messy so a good design system must also be flexible. Local over-rides for one-offs.
You'll need a couple prereqs before you get started:
- A designer that agrees systems are good. Some designers see their work as art. Every element is custom, every button a little different, every screen a new masterpiece. You can't systemize this. You will suffer. Sorry.
- A componentized approach to UI. Use a component-based framework like React, Vue, or Angular. You can do it with CSS classes but this is easier. Trust me.
The main benefit of components is that you can encapsulate both UI and UX. Not just looks but also behavior.
PS: I got lucky and get to do this from scratch. You can introduce a design system gradually but it's a little trickier.
Every select field, say, should look and feel the same. Across your entire app. So why build it from scratch every time?
You want something like this:
And that's your standard beautiful magnificent and all round marvelous select field.
Build it once use it everywhere. ✌️
Test it once, approve it once, back-and-forth with designer once, back-and-forth with QA once, back-and-forth with PM once ... and then it works forever. You're good until the next redesign.
And with a little luck any future redesign will touch just your design system. You might not even have to touch any application code.
Where classes – utility classes especially – fall down is this reusability. Do I have to add
bg-gray flex1 color-blue p3 or was it
bg-gray flex2 color-white p4 🤔
Stop. You've already lost.
Every QA cycle, every PM test, every new feature you will have to carefully vet every little detail. Because they're always done from scratch.
A design system saves you that effort.
3 years ago when I started building my first, the ecosystem wasn't quite "there" yet.
CSS-in-JS or CSS modules? Big fat CSS classes or utilities? React, Vue, or nothing? How to scales? How to colors? Weird names or long names? Build a catalogue or not? How do you docs? Do you even need docs?
Crap, what about responsiveness? Do you grid or flex?
float: left?? 🤨
I've tried it all.
This is what I've landed on as the ultimate solution:
- Use Storybook – spits out a catalogue and docs too. Live preview of your components, human readable descriptions with docs, you can even just write documentation in MDX and storybook handles the rest. Hell it even spits out API Docs based on TypeScript types. 🤘
- Add Chromatic – a SaaS from the creators of Storybook. Gives you a hosted versioned Storybook. Added bonus: snapshot testing of all your components. Screams at you when there's a visual regression 😍
- Use TypeScript – the VS Code experience with TS is just wonderful. Hints and docs as you mouse-over a component are fantastic. Very helpful when you work on a team.
- Start with theme-ui – this part is React only.
theme-uiis the best balance between developer experience/ergonomics and solid design system. Does most of the work for you.
I started from scratch with
npm install @storybook/react --save-dev and 3 days later had a full custom design system ✌️
The trick is to lean hard into the ecosystem and let others do your work.
- Install all the dependencies
theme-ui is your only real dependency. The rest are used in development.
Don't worry about the low version number on
theme-ui. It builds on lessons learned from several earlier attempts.
@jxnblk did a great job
- Configure storybook to be fab
Storybook by default is great. Storybook with some addons is fantastic.
The most important parts for me are:
- easy/automatic documentation
- accessibility checks
- knobs to visually test components
- typescript support
Configuring all this happens in the
Some addons like to be included via the
addons.js file. Others go in
main.js. I still don't understand why.
This configures defaults for every story in your storybook. That is every example you want to put up. Things like adding the theme provider, enabling knobs and accessibility checks, etc.
This part adds the documentation addon, support for typescript, and MDX.
MDX is important because it means you write your design system descriptions once and they double as both testing and documentation. It's great.
- Customize theme-ui for your design
This is the fun part.
theme-ui actually does all the work for you. As long as you don't need custom behavior.
It comes with more pre-built components than you can shake a stick at. All the components you'll need, really.
And it supports themes for custom coloring, spacing, etc. All you gotta do is configure a custom theme for your organization.
Something like this:
Custom colors are the quickest way to achieve a great custom look.
I recommend giving them color names. Primary/secondary/accent gets confusing fast. Especially when variants are in play.
You should map primary to color so
theme-ui default components pick up on your colors. This saves you time.
- Customize theme-ui elements
Once the basic scales are in place, you gotta apply them to different elements. Rather than creating your own from scratch, tell
theme-ui what to do.
A custom input, for example.
And a custom form falls out ❤️
- Use your design system
The best part is that you get to use scales. Scales that you defined in your custom theme.
Look at this input definition, for example:
Lots of magic numbers right? They map to the size and space scales.
pr: 3 means
padding-right: askTia.space 👉 16px
Same for color scales. You say
greyVeryLight and theme-ui checks the color map to get the digits.
And if you need to do something custom, there's the
Some elements come with helper props.
bg is very common,
variant is another.
Beyond that, the
sx prop lets you define everything you'd otherwise use the
style prop for. Except it goes through your theme config.
Also great for adding dark mode. Change theme. 🤘
Here's how it works 👇
And get thoughtful letters 💌 on mindsets, tactics, and technical skills for your career. Real lessons from building production software. No bullshit.
"Man, love your simple writing! Yours is the only newsletter I open and only blog that I give a fuck to read & scroll till the end. And wow always take away lessons with me. Inspiring! And very relatable. 👌"
Ready to Stop copy pasting D3 examples and create data visualizations of your own? Learn how to build scalable dataviz components your whole team can understand with React for Data Visualization
Curious about Serverless and the modern backend? Check out Serverless Handbook, modern backend for the frontend engineer.
Ready to learn how it all fits together and build a modern webapp from scratch? Learn how to launch a webapp and make your first 💰 on the side with ServerlessReact.Dev
By the way, just in case no one has told you it yet today: I love and appreciate you for who you are ❤️