Building design systems

First of all, what is a design system?

A design system is a collection of documentation on principles and best practices, that helps guide a team to build digital products. They are often embodied in UI libraries and pattern libraries, but can extend to include guides on other areas such as ‘Voice and Tone’.

Or, in other words, it’s a set of UI elements and rules on how to use them.

Design system illustration. Popular style of illustrations

Why do we need design systems?

In order to figure that out, let’s imagine a 150-page project that you have to visually improve and make it more user-friendly. You have a product hypothesis that the visual style of the application will influence the conversion of the users into paid accounts, for instance.

The first way is to ask your designer to draw all the 150 pages. It will take too much time and money but you’ll see this new design on the whole application. You’ll be able even to build an interactive prototype and try to work with it.

The other way is to ask a designer to draw the key elements of the website and the templates for the main pages to be forwarded to a developer afterward. The designer then gives his feedback based on the results of the work with some changes to the ultimate version being made.

This last approach sounds way cheaper and quicker than the first one, but from the outset, both of them do not provide you with the full picture meaning the ultimate redesign of the product.

The second approach is exactly what design system is all about. We do not spend a lot of time drawing the total number of pages but describe only key approaches and elements saving our time.

We see a huge difference, though, when it’s time to make changes in the middle of the process. Imagine that a designer has finished 150 pages, then passed them to a developer and suddenly the in-place editing. And now the designer has to fix those 150 pages and again forward them to the developer for implementation. Design system makes it so much easier. You change a certain principle and just a component responsible for it. In the design system, we transfer to a code not only the elements but also the principles of their unification. We can thus fix it globally throughout the project.

The first approach is more like Waterfall and the second one is closer to Agile.

Design system objectives:

  • Maintains the visual order while working on a project
  • Makes products visually consistent
  • Accelerates big projects development
  • Allows more frequent changes

Design systems examples

https://github.com/alexpate/awesome-design-systems

Design system is quite widely spread and used. Banks, car manufacturers, financial companies create their design systems to launch their products on the market as soon as possible. Design systems are used by Audio, Alfa Bank, Atlassian, Google, Alibaba, Gov.UK, Apple. Standardization contributes to quick enhancement.

  • Banks
  • Audio producers
  • Governmental portals
  • Internet-companies

Design System is comprised of:

Traditionally the DS contains a set of rules which describe a visual solution to your product. These might be the styles of basic elements, color scheme, and components composition principles. In other words, it has everything that the ultimate design envisages but in an articulated way in accordance with strictly described principles and not in the form of a design layout.

Apart from basic components the design systems usually include main pages and blocks templates in order to give an idea to developers as for their further merge.

Try to remember any brand book of a decent agency. It has not only logo, letterhead template or business card template. It usually includes the explanation of how to use the logo, brand pattern or font so that the result is in full compliance with the vision of the designers. And if you have to color the delivery car, you want to consult the rules applicable to that in a brand book even if a designer wasn’t thinking about it while working on it.

The same goes for design systems. They enlist the basic principles of working with key design components and their merge and provide some examples of their usage.

  1. Visual style basic rules
  2. Style of components
  3. Components’ composition rules
  4. Pages composition rules
  5. Animation basic rules

 What do we get?

It gets both easier and more complicated for a designer. When we need to add a page in a product, we only have to compile it from the existing templates and elements.

But if it has to be a drastic change in the whole system, it calls for careful consideration of how this one change will influence the system as a whole.

We get a high iteration speed but it is a designer who is in charge of the elements concurrence in the ultimate product.

  1. A new designer does not create style anew
  2. New functional is the composition of existing components
  3. Rapid launch of new functions and products

Building new page from existing UI components

A connection to front-end

Let’s say we have a design system. What’s next? We have to put it to code – to create a library of components otherwise each time while developing new products developers would create new components and might partially violate the principles. Moreover, it happens at the cost of designers’ time to check the result.

Unified design system is a unified component library.

Rules of layout

In order to create design systems within a code in an effective way, one should stick to a set of layout rules.

Create a layout for each separate component

Let’s say we have a design system and a developer has made a one-file layout as in usual landing without taking into account component independence. When we change a component in a design system, the problem pops up. The reason lies in high interconnection between components and in the absence of a separate part of layout responsible for this or that component display.

Conclusion: component layout

All or nothing

All or nothing

Components are independent entities. either you use them all, or don’t use at all. For example, if you have to add space from the button, you add a wrapper and put a space to it. By doing so we do not modify the components themselves. They are independent and the logic of their usage doesn’t influence the display.

Bad example

<Button className="some_class_with_margin">Send</Button>

 

Good example

<div className="some_class_with_margin">
   <Button>Send</Button>
</div>

 

Block Element Modifier

Say Hi to BEM —  Block Element Modifier

  • Block is a component
  • Element is an element within our component
  • Modifier is variant of our component

A component has a limited number of variants meaning a limited number of states which the component is able to acquire.

Good example

<Button variant="primary">Primary button</Button>
<Button variant="danger">Dange button</Button>
<Button variant="info">Info button</Button>

 

Bad example

<Button color="#00ffee">Colorful button</Button>

 

In a good example, the Button component has a limited number of states. It fits 99% of components. Such an approach allows for testing and displaying all the possible variants of components which is a limited predictable number of states.

Atomic design principles 

http://bradfrost.com/blog/post/atomic-web-design/

We created a layout of our components: they are independent and may have an unlimited number of conditions. The best way to classify the components is the atomic design guide:

  • atoms
  • moleсules
  • organisms
  • templates
  • pages

Atoms are our components (Button, Input, Icon) which are inseparable, just like atoms literally;

Molecules are sets of atoms to be unified. For instance, it might be a field and a button, or a headline and text.

Organisms are blocks positioned by atoms and molecules. For example, a header or a block with a user’s profile;

Templates are common components which can be set into the final pages;

Page is a final result, seen by the user.

Once we have broken down our application into reusable entities, our final pages should not contain any new layout: it should only be compiled of reused parts.

Now let’s imagine a situation when you have to compose a new page. The designer or the product owner describes which data you should add, after that you figure out which template you should use. Next step is integration: receive data, add it, integrate forms, create tests. We don’t create the UI from scratch every time; we reuse the existing elements and patterns.

Component creation rules for React JS

We won’t create something from scratch but apply SOLID principles to our components. SOLID, as a rule, is referred to in terms of OOP, but it is also applicable in functional programming. And this is the case of React JS.

SRP. Single responsibility principle

Logic stays clear. We try to create components so that it’s easy to give a description of their field of application.

  • Button – button style
  • TextInput – input style
  • Icon – displays the icon of SVG code
  • FormRow – spacing logic between form strings
  • Grid – standard spacing logic between elements/blocks on a page
  • FormField – input positioning input, validation errors and integration with redux-form

FormField description takes some effort. The part of the integration with redux-form may be put in a separate component.

<Button variant="primary" type="submit">Submit</Button>

 

This code will obviously make a button in a primary style with Submit text and submit type.

OCP. Open/Closed principle

We’ll deal then with composition. In order to change the icon next to input, we don’t have to add a new modification. We have to provide a chance to add the text from the outside.

Bad example

<Input icon="close" />

 

Good example

<Input icon={<Icon name="close" />} />

 

LSP. Liskov Substitution Principle

We can apply this principle as a way of component substitution into the ones capable of extending the allowed type. For example, we can create Suffix property in Input component and add both the icon and the text there. The logic of our component’s work for this property will stay the same: we’ll still display the content to the right from entry field.

Input.propTypes = {
   suffix: PropTypes.node,
};
<Input suffix="UAH" />
<Input suffix={<Icon name="calendar" />} />

 

To put it simply, as in any functional programming language, here we deal with the function composition. Our React components are functions themselves, which acquire properties at the input, and provide the layout at the output (JSX). Our task is to create such components which can be easily compiled into a composition. So try to figure out if you could take any component and position it in a certain way without any limitations as for the text string instead of displaying the text next to entry field.

And finally, restrict the number of the components’ variations. A composition is a perfect thing, but the outer modifications of components’ style and behavior best be avoided.

Storybook

https://storybook.js.org/

We have described our components and now let’s proceed to development process organization. Since our components are independent entities, they can be developed independently from the pages they are used in. If the logic of elements’ composition is separate from the elements themselves, there should be no problem at all. We simply replace one element with another one without breaking the structure of the page/block.

Storybook might be helpful. It is a tool for creating interactive libraries of components. On the one hand, it provides an independent component preview that actually allows for creating components. On the other hand, we get a visual documentation of our design system.

And now when a new developer joins the project, he/she will instantly see all the existing components and how to use them.

A story is a demo version of a component. Stories can be grouped to facilitate search so organize in a way that suits your team. We have type grouping in our projects:

  • components
  • containers
  • blocks
  • forms

And the stories inside are grouped by the property name:

  • components/Button
  • components/Input
  • forms/SignupForm

And every property has a set of demos

  • components/Button/General
  • components/Button/Link

Write story first

 

When Storybook is introduced to a project, developers mostly tend not to use it and do not quite get the reason for it. And here the analogy with tests suits well. They seem to be useful and necessary but few people to write them, though they accelerate the development of big systems.

Stories have a similar situation: without the Storybook we would have to add a component on a page in a process of its development/ testing. But that doesn’t make any sense since the components are independent and can be developed separately. And this is the point when we need some help from Storybook which may be transformed into a perfect documentation given some extension.

The same as with TDD principle – write a test first, we can coin a new principle – write a story first.

Best practices

There are a couple of rules we follow while working on components.

fullWidth

The default is on for the block elements. And the block expands on the full width of parent block which allows us to adjust its width with a parent element without determining all the variants of the width inside the component. All or nothing.

For string elements, e.g. Button, the default is off. But we can pass it and expand the button on a full width.

Variant

We standardize the name of the property Variant for all the component variations. We do not use type because we have standard HTML attribute type, which should be used with buttons and inputs with different styles of displaying set to them. A variant is absent in HTML attributes, though.

Variants examples:

  • Button (primary, danger, info, success)
  • Input (default, inline, dashed)
  • Checkbox (primary, danger, gold)

value, onChange

All the entry fields and elements which are used in forms, we use the standard Value property interface, onChange, to facilitate integration.

Grid

A grid can be used not only for column layout. It can also include the logic of spacing between elements (e.g. 8, 16, 24). If you use it in your project, in 99 out of 100 cases a designer won’t be able to tell that you have a wrong space.

Trends

When you have a design system and you know how to work with it, your application is made from reusable blocks. You have simple visual components obtained from design and put into code. So we compile the pages out of them and integrate.

It’s been a while since front-end developers lived with an idea of layout automatization. Some handle this by creating special tools and visual editors, some resort to the creation of neural networks. I’m more like a tools person than an AI one, so let’s talk about them.

The first tool that I personally used was Word, yes, exactly. My first website with car pictures was made in Word.

Then followed  Dreamviewer, Adobe XD, now it’s  Figma. The main idea of such tools lies in the fact that it’s a designer who creates and checks layout. And his draft is actually the layout with the program doing all the job under the hood concerning the conversion of visual blocks into the markup language.

The stumbling point is the layout quality. A perfect layout presupposes reusable style blocks, clean and well-structured code. Not all the designers have managed to get this clean code. Table layout, absolute positioning of all blocks used to be the usual results for such a program.  But that’s not enough.

Figma and AirBnb developers are currently doing a breakthrough. Both teams aim at exporting React components directly from design. If they succeed, then our components will be exported from design and front-end developer will have to figure out how to compile them together, to get and send data. The responsibility for breaking the design down into components and think of the structure is now delegated to designers. I wonder how it will work in terms of variability of components but I believe in success meaning exporting components from design.

Front-end developer opens an editor, sets components’ property names and adjusts exports and then assembles the application out of it. We automate a monotonous process of layouting: designer draws, developer visually breaks it down into blocks and recurrent templates, writes a code. Everything is done by a designer with minimum errors made.

It’s similar in a way to iOS component editor: we click the element, choose its property or put a processor on the event and it gets in this component’s controller (might be mistaken, I haven’t been developing on iOS for quite a long time and it might have changed a lot since then)

Automatization of transferring the design or design resources to a developer is now commonly known as Design Ops, similar to Dev Ops. The point is in minimizing of design editing or exported developers’ resources.

For example, we export the icons from design or pictures and they get directly to the application folder where the application employs them. We don’t have to work on them any longer. Such automatization allows us to speed up the process of changing app resources or adding new ones while reducing the number of errors.

Nowadays, it’s easy to configure the export of SVG icons directly into the project or configure it so that these SVG files will generate the font or a file which will be used in application afterward. You don’t have to use a special program or resource, e.g. Icomoon, to generate a font; you just add the icon to a folder and the font generates automatically during assembly stage.

Conclusions

Design systems and new tools reduce the gap between designers and interface developers. All the efforts help to accelerate the launch of quality products and make modifications. Of course, current performance is way far from perfect but I believe in the ultimate result so I’m adjusting my projects for tomorrow’s opportunities starting today.

It doesn’t take much: stick to component approach, create design systems both for codes and for designs, and you’ll be able to seamlessly adapt to evolving opportunities.