How to build a Design System?
Hi everyone, I decided to write my first article in order to share my experience and my personal opinion related to the creation of a design system on a large scale product.
Thanks to my professional experiences, I’ve been able to work twice, from scratch, on a new component based design. I won’t talk too much on the main idea of the Atomic design methodology, but I will try to tackle some assumptions I or my colleagues had during the development of such a library.
Is a design system blocking the designer’s creativity?
It’s a logic apprehension we can all have when we try to automate our daily work. Especially about the creative process, what’s happening if we try to standardize it as much as possible, from the inspiration steps to its implementation?
Building a consistent design system is only the first part of the process, and might not be the hardest one. Once you have your library ready, it’s not always that easy to maintain…
- How to make it consistent across all of your platforms (Android, IOS, web, etc.) or/and devices over time?
- The process of the addition of new components needs to be really strict otherwise it’s gonna turn into a big mess with many ways to handle the same situation.
- Never forget to deprecate the old components (or even to remove them if possible on the newest versions).
- How to update a component used everywhere without breaking everything? (drawback of the component based design :))
The last point is really important. Having a design system developed and on production doesn’t force you to always use the same components for ever. In my opinion, some regular creative sessions are important to improve the quality/efficiency of the components (user tested !).
This part can be a real pain for the developers for the reasons above.. But it’s always necessary to challenge what we do, and it’s actually a great puzzle to resolve all the time :) (assuming you like puzzles..)
Mindset
(1) Tell me how it works, not how it looks like.
Few years ago, I realise that every time I was developing the UI of a new website, I was too focused on the visual output instead of the functionality itself. Now, I like to think of a component like an API.
Let’s say we are building a new wonderful button component. Here is how I would approach it:
- What kind of actions am I allowing the consumer of my library to perform? (click, focus etc.)
- What kind of native state should I support? (active, disable, empty..)
- What kind of custom states do I want? (blue button, red button..)
Everything should be explicit, testable, and obviously, documented. And guess what? That’s something which should be done between a designer and a developer to cover all of the situations.
(2) Restrictive and Flexible… Wait, what?
Yeah, I know, it can be very contradictory, but it’s actually not that crazy, I swear. If you want to implement a specific behavior, like a button for example, you don’t want to have 5 different ways in your design system to do so. It needs to be restrictive in that way.
However, it’s necessary to think generic in order to cover all the specifications of the component (and to plan the future usages… without overthinking it :))
One good way to do so, is to think about open sourcing the library. Is it an objective to do it for you? Maybe not. There are many good reasons to do it (opening to the community, receiving constructive feedbacks etc.), and it’s always good in my opinion as a company to release a design system. Benefits of the open source apart, by thinking that way, every components will be built in a generic way.
(3) No context in this concept.
This one is not always easy to do. First of all, I think every components should be agnostic of the context. I don’t need to know where my button will end up in your design or to think about what would happen if there are two buttons in a row. The component needs to handle perfectly everything on its own, that’s it.
- The layout? It should be handled either by the grid provided by the design system (which I’m still not 100% sure yet) or by your own system.
- The actions of the component? By callbacks! If I click on the button of the design system to perform an action, I just provide a callback action supported by the component and that’s it.
- Business logic. Something too related to a platform shouldn’t end up in a design system library.
For example, at Blablacar, we are currently working on a new design system (I know, surprising!).
We have some cards on the mobile website we might not keep on our new library. It’s only designed for the company dataset in a search context, and I don’t see how this could be used in another context.
Moreover, this exact component used to include some margins, but it’s not its job to handle the layout. We used to have it, and honestly, it can turn into a mess to maintain with a lot of hacks (negative margins etc.).
Atomic design
Remember when I said I was not going to talk about Atomic design? Well, I lied.
I think it’s a really great methodology, and I was really inspired by it, even if I like to adapt it a little bit…
Here is how I see it:
- Atom (Core of the brand): Colors, Fonts & Font-sizes, Spacing & Responsive layout system (grid).
- Molecules (Low level components: Buttons, Textfields, …
- Organism (Components/Widgets): Modal, Topbars…
And that’s actually it… so far. The templates and the concept of pages should be handled directly in the main application, not in the design system.
Animations
In order to be really flexible and consistent, the idea is to share the configurations (atoms) and the small components as much as possible inside of the library to build all of the components. If a color is changing over time, or if you wanna make your configuration editable, everything will update accordingly.
However, the animation is an interesting topic in a design system. If I want to share an animation (a full animation or a part of the behavior), how would I do it? Is it even a good idea on the long term? I don’t know (yet). But there are several ways to think about it:
- Every components will handle their own animations.
- Every components will handle their own animations based on a common configuration file (basically putting an animation object into the atoms with the animation durations etc.).
- Thinking about the animations directly as components?
The first two options seem pretty much obvious in term of implementation, but about the last one, it can be really interesting. That way, the animations wouldn’t be tied to a component and can even be built/updated separately by interactive designers. We can also imagine to compose ourself, as a user of the library, the transitions/animations of the components.
How can we work together effectively?
First of all, I would like to tell you why I like to be a front-end developer. We have the great opportunity to innovate, to ship final features in production with the collaboration of “many people with a different job”. SEO, Accessibility, Design, Backend, Performances, Security, Content… A lot to manage and to centralise at the same place.
Particularly with the designers (because that’s our focus in this article), I’m interested in the way we can efficiently work together. Why am I saying this? If you work on a “one shot” project you don’t really have to maintain, that’s quite easy. But for a long term and large scale project, that’s completely different.
Production never makes it back to the designers
When a developer implements a mockup, it’s going to production with the state A. Your company might have a velocity of 10 releases/day, or even 1 big release of thousands of lines per day. On the following weeks, another team can update your component, a new contract with a third party service… Or even on the developer side, we can decide to refactor some elements with the Product Owner or implementing some A/B testings…
Anyway, my point is, the production is not immutable while the mockups are, and usually stick to their major releases states.
And how the developer can get these mockups? Sketch / Photoshop / Invision / Zeplin / MarvellApp / Origami / Wiki specs… Careful guys, the JS fatigue is coming to you :)
And there is Airbnb (one more time). I tried quickly React Sketch and.. Problem solved! By using the web React components to design, we can be sure the design is identical to the production.
When do we deal with translations?
That’s actually not a real problem itself, or more exactly, not the good question to ask. The problem is: for the same content, depending on the language, the text could be 1 word long or a 2 lines sentence.
As a developer, I always feel the aspect of text volumetry is forgotten in the specifications. It’s really important, even more if you are working on a responsive website. It’s important to know for each component what kind of content we can allow. Number of lines? is there some ellipsis? max/min width? Viewport based?
This could define a lot in term of front-end implementation: CSS units (ems, px, etc.), media queries (viewport based, JS calculation, etc.)
How to be consistent across platforms?
It depends on your objective, but today’s big trend is to unify the experience on all of the platforms. Why should we build a different experience on mobile web than the native apps? Or even between the apps, why should we create different designs for iOS and Android?
By removing this design constraint, we create another one. Every time we are creating a component, we need to be sure this feature is supported or even doable on all of the platforms:
- Is it compliant with the Apple and Google guidelines?
- Is the rule supported by the browsers?
- Can we unify the experiences without getting rid of the native elements?
Front-end part
Let’s dig a little bit into the web development and the consequences of everything I said above. For such a project, I would recommend you to have some values associated to your design system you shouldn’t forget:
- Accessibility first.
- Atoms externalised in a separated configuration.
- Component fully unit tested and accessible by the designers.
- Versioning & precise changelog.
- Text specification attached to each components.
- Easy to import everything or parts of it.
And here is the front-end stack I am currently using:
- ReactJS
- JEST, Sinon and Enzyme
- CSS in JS
- Storybook/React Sketch
CSS in JS, here we are
That’s an interesting topic in the front-end world nowadays. Why in the hell would we use the CSS in JS? I could answer that, before the JS templates, we didn’t want to put HTML in JS either. But to be honest, I don’t like that.
The only reason I decided to dig a little bit into it is because I faced a problem which the CSS in JS seemed to fix by itself:
Long story short, if we create the front-end design system in a different repository than the main application (which we did), I would like to provide components you don’t have to compile. I also don’t want to force you to remember that, if you are using this component, you also need to import manually the CSS attached to it.
Since we cannot attach a CSS file to a JS file natively… I tried CSS in JS (Mhhh… let’s say, some of the hundreds CSS in JS solution). And it worked perfectly so far, but I would be glad if you prove me wrong about it :)
And… That’s it!
I will try to write another article, a bit more technical focused on the stack I’m using on a daily basis, but I really wanted to talk about methodology first.