Creating a Design System in React

How to build a design system using React, Bit, and friends.

Jonathan Saring
May 26 · 9 min read
React Material-UI reusable component system

Design systems are one of the hottest trends in modern web development. They are used by anyone from tech giants like Airbnb and Uber, to small startups which favor UI consistency and code reuse.

Modern user interfaces are composed of many atomic components. Each component encapsulates the visual and functional properties of a certain element in the interface. Different components put together can create different experiences for application users.

When building many projects, organizing components into a unified system can save time through reuse and help ensure that your users get a consistent experience at every touchpoint. This can tremendously help to speed up and standardize modern web development, at any scale.

How Uber Design does components

Design systems serve as a bridge between developers, designers and other stakeholders in the process. To a developer, a design system has a unique meaning. It’s the actual set of modules used to build the app.

In this post, we’ll learn how to create an effective design system in React and successfully distribute it for synchronized usage across your applications.

Here are the key parts we’ll cover:

  • Building (in isolation)
  • Distributing
  • Documenting
  • Adopting and collaborating

There are many great tools for design systems. In this post we’ll be working with Bit, which effectively facilitates the management of React components. Examples can be explored here:

Building isolated components

Every React design system is made of components. When we isolated components, we can make sure they are out-of-the-box useful.

We’ll use Bit as a workbench to isolate our components. This will let us develop them “outside” of the project, and get feedback if each component can build, test, and render in isolation.

Then, we can use Bit to version each component independently and to define and control the relationships between components, in every application.

Isolating

Developing components in isolation means decoupling the components from their project’s context. This makes sure that each component can be introduced into different web applications.

Bit provides a way to isolate components in the project. It places each component in a “Capsule” which is basically a container for components.

The Capsule contains all the component’s files and dependencies, which are automatically defined and added to the Capsule using bit add.

For example:

$ bit add src/components/*

Thus, allowing the development of each component as a standalone unit, outside of the project’s context. It has everything it needs to run alone.

Building and testing

As components are isolated, it becomes possible to test their reusability.

Using Bit you can define a development environment for every component in the project's workspace. These environments are reusable and can be applied directly to all components in a given project.

When building a React design library, for example, the react or react-typescript environments can be applied to compile the code outside of the project and make sure it builds even after changes are made to the code.

To apply a build environment it can just be added to the components:

$ bit import bit.envs/compilers/react-typescript$ bit build

The same idea goes for testing. A reusable tester can be applied to the components, which tests each component in complete and total isolation.

The tests will literally run outside of the project, and so the results will indicate if every single component (or changes made to it) passes or not.

$ bit import bit.envs/testers/jest$ bit test

Documenting and rendering

Quick visual feedback is a powerful way to develop components.

Bit generates documentation for components published on bit.dev, by extracting information from its code (TypeScript, PropTypes and JSDoc comments) or by presenting the component’s .md file (if such is available).

Storybook is probably the most prominent tool used to locally render components. It can be used with or without Bit. In Bit’s next version, according to the official specs, local rendering will be added as a native part of the development experience. It’s expected to support the story format too.

Distributing components

The main goal of the design system is that its components will be consumed and used in other applications.

To do so the components need to be versioned, published, and then imported into other applications. With Bit there’s no need to version and publish the library as a single package. This means not having to install, update or run an entire library just to use or change a single component.

Instead, it becomes possible to version each component independently (learn why), define and manage relevant dependant components, and publish it for standalone reuse.

Versioning

When different components in a project are differently versioned, the project becomes a “multi-component” project, also referred to as a “monorepo”.

Bit automates the versioning, updating, and management of many components in a single project. Using the bit tag command a standalone semantic version can be applied to all components at once.

For example, running this command for the first time on a new library will apply the version 1.0.0 or 0.0.1 as you choose, to all components.

$ bit tag

When there’s a later change to one component, like button, its version can be bumped without having to bump other components. A bit status command will show the exact version and state of all components in the project.

And, if there’s another component depending on it (e.g. submit-form can depend on button), Bit “knows” it should also bump the dependant components and update them with their new dependency version.

Publishing

Traditional design libraries were versioned and published as a single package. This approach is mainly the undesired result of the node module oriented package manager system, which was not built for small components.

Using Bit every component can be independently packaged and published without having to refactor the library or work too hard.

Components are published to a remote scope. They can be those on an internal server or in the cloud, in cloud platforms like bit.dev.

Once versioned, components can be published using bit export while specifying the designated scope on bit.dev, as such:

$ bit export user.scope
# 2 components were exported to owner/my-collection

Once published every component can be consumed in one of two ways.

  1. It can be installed as an independent package using npm/yarn.
  2. It can be imported using Bit to locally develop its source code.

This combination makes it possible to consume independent components instead of entire libraries and to locally edit and update any component right from consumer applications, to overcome any adoption barriers.

Updating

From an organization's perspective, it’s crucial to be able to constantly deliver updates to UI elements in different web applications.

Using Bit it’s practical to deliver -and get- updates only to parts of the UI of every application.

As each component is independently versioned, a new version can now be released only for a specific component. Consumers of the update will not have to update the entire application and don’t have to update the versions of other components unless Bit prompts that they depend on the changed component.

An integration between GitHub and Bit.dev can be used to automatically create a PR to every application using a component, asking it to update to the new version. Teams can learn exactly who updated what and where.

An integration to Slack also notifies relevant stack holders on new updates, so that they can update their apps, review changes, and join the process.

Documenting components

A design system in the focal point of collaboration for developers, designers, product managers, and other stakeholders.

As such, discoverability and documentation of components are crucial foundations of any design system. Some teams choose to build their own documentation portals (see the beautiful Grommet website) and use different tools to document component APIs, examples, and more.

As mentioned, Bit React components are documented using standard documentation formats. It analyzes, extracts and visualizes them.

On the bit.dev platform, documentation becomes an integral out-of-the-box part of your React component system. So instead of creating and maintaining a docs site for the library, the actual component system in the documentation.

Search and discoverability

Bit.dev indexes components with relevant information such as context (react, angular etc), labels (button, forms etc), weight (bundle-size), dependencies and more. Components can be then quickly found by these parameters.

Examples

Several tools provide an interactive experience for component examples, including Codesandbox, Storybook and more.

In Bit, examples are in fact compositions of the component which are rendered in an interactive environment, locally or in the cloud. This helps improve the development of components, and also creates a beautiful documentation gallery that people can try and test hands-on.

API reference

Bit extracts the API reference of React components (using react-doc-gen) and presents it as part of the component’s documentation for quick usage.

Example API of the Semantic-UI `tab` component

It will update as the code does, so there’s no need to manually update the API docs in multiple places. It’s built into the same place where components are hosted, managed, and reused in different applications.

Test results as docs

Testing is a critical part of building with components.

Unit-test descriptions and results also serve as a key part in the documentation of components, as they describe results expected from the components in different use cases and contexts.

Adoption and collaboration

Creating adoption for a design system is no simple task. Many app developers resist adopting the design library for a number of reasons, such as:

  • People can’t find components.
  • People can’t make changes to components.
  • People don’t want coupling to the library.

To overcome these barriers Bit provides two rather unique features.

  1. Everyone can share components to the system — Bit “legalizes” and greatly eases the creation and publishing of components so that every developer can now publish components to the organizational pool.
  2. everyone can import and locally change components — Importing components’ source-code into consuming projects for local modifications, while still getting later updates on top. This breaks the barrier of not being able to modify components from the library.

Instead of a one-way street where one team sends a large package with many components for everyone else to use, and those other people often need to write their own components that are missing in the library, this helps to create a collaborative component ecosystem where people build UIs together.


Thanks for reading, and this is just one take on creating a modern web design system through components, leveraging Bit as a workbench to drive component development, reuse and grow collaboration. Please do feel free to comment below, ask anything, or share ideas. Cheers 🍻

A note In Plain English

Did you know that we have four publications and a YouTube channel? You can find all of this from our homepage at plainenglish.io — show some love by giving our publications a follow and subscribing to our YouTube channel!

JavaScript In Plain English

New articles every day.

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store