Building a React Design System

Build a reusable React design system to speed and standardize web application development.

Jonathan Saring
Bits and Pieces

--

Uber Design base design system

Design systems are a highly effective way to ensure a standardized, consistent look & feel across your screens and apps. This, in turn, helps to reduce user confusion, increase satisfaction, and helps your brand grow a loyal fan base.

For most top companies, design systems are implemented as a reusable set of components in React, Vue, Angular, or even Stencil. This makes sense, as it gives developers the ability to share and reuse components to build different apps, which boosts development velocity as well as UI consistency.

In this post, we’ll cover an effective modern way to build a component design system in React, and how to increase the chances of this system being adopted and utilized to speed and standardize web application development.

Streamlining component development, documentation, and reuse…

hThe Bit.dev base-UI design system

Your goals are to speed and standardize the development of web applications, so this means you need to create a system where developers can build, share, and collaborate on React components.

There are a few ways to go about it, but one prominent toolset built specifically for that purpose is Bit (GitHub).

Read: “How We Build a Design System

It streamlines component development, reuse, updates, and documentation so that your design system’s components can be used to build your apps.

Bit’s CLI tool helps you develop, isolate, version and publish components in a project. It also manages changes to components (with automated dependency control) in different applications.

The Bit.dev platform is a cloud library for components, where they are documented, visualized, and can be consumed into more projects.

We’ll see how this modern toolset can help solve a few major challenges when building your React component system:

  1. Developing and publishing components.

2. Documenting and reusing components.

3. Managing component changes and updates.

But first… an example, please?

I guess some of you are familiarized with HP’s great “Grommet” React library. It’s how teams at HP build the standard frontend with React.

Using Bit, this library becomes a reusable system of components, while each is independently packaged, versioned, published, and documented.

Grommet reusable component system on Bit.dev

Each component can now be installed or even sourced right into different applications, and its owners can release focused updates to everyone.

1. Developing and publishing components

A lot has been written about building reusable React components. There are also some great guidelines on how to create reusable components in React.

Components can be bound by their context in many ways: dependencies, build configs, styles, states, and more.

The most important part of reusable components is isolation.

Why? because when we isolate components we can learn if there are reusable or not, and act to make sure they are truly reusable.

Isolating React components

Bit’s basic functionality is to isolate components from the project.

To do so, it places each component in a “Container” called a “Capsule”. Every container automatically includes all the components files, dependencies and configurations. Bit streamlines this process for you almost entirely.

It will automatically define each component’s file and dependencies for you. And, it helps you learn about other sorts of coupling so you can improve.

For example, let’s assume this project’s folder structure. It’s a basic set of components inside a Netflix-like React movie application.

├── App.js
├── App.module.scss
├── App.test.js
├── components
│ ├── hero
│ │ ├── Hero.js
│ │ ├── Hero.module.scss
│ │ ├── Hero.spec.js
│ │ └── index.js
│ ├── hero-button
│ ├── item
│ ├── list-toggle
│ ├── logo
│ ├── navigation
│ ├── title-list
│ └── user-profile
├── favicon.ico
├── global.css
└── index.js

To start we create a workspace in the project where components are managed. Then, using the bit add functionality we can “tell bit” where the components are located. In this case, it will be src/components .

$ bit add src/components/*
# tracking 8 new components

What just happened? Component isolation!

Bit scanned the folder and identified the components. It analyzed the code of each component to decide if it has any additional dependencies such as external files of packages. It then placed each component in a Capsule.

This also means that Bit now knows about the dependencies between every component and other components. So, later when we version the components, we can easily update navigation when item changes.

Controlling the status of components in your project

At any time, the bit status command lets you view the status of all components in your project. It will help you learn if every component is successfully isolated, versioned, and passes build and test in isolation.

This is very useful for developing reusable components. Why? because it helps you learn about the coupling between each component and the project.

For example, running bit status after bit add on this demo project, will point out to you that some components are missing the styling file.

$ bit status> hero ...  missing dependencies
src/components/hero/Hero.js -> src/global.css
> hero-button ... missing dependencies
src/components/hero-button/HeroButton.js -> src/global.css
> item ... missing dependencies
src/components/item/Item.js -> src/global.css
etc...

Great! We just learned how to make our components more reusable. For example, we can aspire to apply encapsulated styling to each unit.

To solve this with Bit, you can tell it to add this file to the components

$ bit add src/global.css --id style/global
tracking component style/global:
added src/global.css

And now bit status will show:

$ bit status> hero ... ok
> hero-button ... ok
> item ... ok
> list-toggle ... ok
> logo ... ok
> navigation ... ok
> title-list ... ok
> user-profile ... ok
> style/global ... ok

Reusable dev environments for components

If each component is reusable, it should be built and tested on its own.

You can use Bit extensions to define a reusable build and test configuration for each component. These extensions become a part of the component, so Bit can run them outside of the original project. Literally.

To apply extensions on components, you add them to the workspace.

Then you can use bit build or bit test to run the components in isolation from the project, and learn exactly if each of them is ready for reuse!

Versioning

The Bit.dev homepage composed of independent components

Versioning independent components is extremely useful.

It helps compose pages and apps from independent components, which can be independently changed, updated, and replaced.

Take a look at Bit’s homepage. Did you notice the hover effects?

It shows you that every component on the page is independently versioned. They were built an published in a different library called “Evangelist”.

Let’s get back to our example project above.

We can use bit tag to version all components at once.

$ $ bit tag --all 1.0.0...9 components tagged | 9 added, 0 changed, 0 auto-tagged
added components: style/global@1.0.0, hero-button@1.0.0, hero@1.0.0, list-toggle@1.0.0, item@1.0.0, logo@1.0.0, navigation@1.0.0, title-list@1.0.0, user-profile@1.0.0

Now Bit “knows” what is the version of every component.

If now you make a minor code change toitem you can simply use bit tag to bump it’s version to 1.0.1 . Bit “knows” which other components are dependant on it, and will bump their version too if you choose so.

This gives you modular control over the development of components.

Publishing

At any moment you can publish your versioned components to bit.dev. You can create a collection there, it’s free for OSS and limited private code.

Here’s what the demo project’s collection looks like.

Or, set up your own distributed bit server if you prefer.

To publish the components use bit export with the destination collection, and the components will be sent to the cloud.

$ bit export <user-name>.<collection-name>

2. Documenting and reusing components

A very important aspect of creating a React design system is how you document components and make it easy to reuse them.

Documenting

There are many great ways to go about it- from popular tools like Storybook to live examples on Codesandbox or a self-made website.

Since Bit.dev is the hub for component reuse, it also provides a home to our component documentation with auto-extracted API reference (react doc gen), visual examples, test results, and more.

Starting from Bit’s next version (due summer 2020), it will also support Story files.

Organizing and searching

When working with many components, it becomes critical to be able to find the right components to use.

For that Bit.dev provides a search feature built for components. It lets you search by component labels, context, and even bundle-size.

Labels are especially useful for quick classification of components.

Example `tab` component labeled with `nav`, `react`, `tab`, and `ui`.

So now if I’m working on a team that builds the design system and I publish 100 components, it becomes easier for app builders to find and use them.

Reusing

From bit.dev every component becomes standalone available to consume in one of two ways:

A. Install it with npm or yarn — directly from the bit.dev registry.

B. Use bit import to source the component in another project.

This means that you and other developers can now start using every single component in any application.

Using npm install is a fast and simple way to go about it. Using bit import is how you can make and even publish changes to a component directly from another repository, which can be useful to speed project development.

3. Managing component changes and updates

So now you’ve got the basics of creating a reusable system of React components, on the technical side.

But life is often more complex.

A design system is more than a library. It’s more than the colors of your components. It’s an ever-growing and ever-evolving source of truth for the basic parts from which your entire product experience is made of.

Therefore, changes are bound to happen. Constantly.

Traditional libraries force you to release a new version of the entire library every time you update a component. That hurts the users of the library.

With a cloud library, you can just update a single component. And, you can make sure this component is updated in every one of your applications.

Releasing updates

To update a component in Bit.dev you’d have to publish a new version. This means using bit tag to bump the version, using bit status to see which dependant components need bumping too, and publish the update.

That’s it. The update just for this component is now available. People that don’t use the component won’t have to update an entire library for no reason.

Getting updates

When there’s a new component version available, consuming projects can bit import it into their projects and update the component.

If they previously imported the component and made local changes to its source code, the two versions can be merged with Git (`bit checkout`).

If they merely installed the component as a package, the version will simply be updated for every component that is impacted by the change.

Integrating GitHub to control updates

You can integrate Bit.dev with GitHub. That is to control the updates of components in different applications.

Integrating your GitHub repositories to your Bit.dev components gives you both visibility and control over the updates of components.

Every time there’s a new version, the integration will create an automated pull-request in every repository that uses this component!

Then, you can track and learn which repositories accepted the changes and which ones went rouge and did not choose to update.

So, maybe for the first time, you can not only update specific components in different applications but also to streamline and monitor these updates.

Integrating with Slack for update notifications

Finally, you can make sure that not only repositories get component updates, but people also get them too.

Integrate Bit.dev with Slack to make sure that every time there’s a new component version available, relevant people will know about it.

Just for an update that my teammate Eden Ella updated a component

And now, you can send and many updates as you need and make sure that you know exactly which teams adopted the updates and which didn’t.

Designer <> Developer collaboration

Collaboration between designers and developers is a pain point.

The words “Design System” has different meanings when talking to a designer and a developer. While designers refer to visual elements and style guides, developers refer to components implemented in code.

In order to unify a design system into one source of truth, we need to give designers visual interactive access to the actual code of the developers.

Instead of just “burying” the code of the components in a source-code repository on GitHub, Bit.dev lets developers place and manage all their code components in a shared collection- in the cloud. These are the actual code units the developers build, share and use across their apps.

Every component is visualized so that everyone can see and edit examples.

Designers can review new component versions for example. They can access and review all components in one place, and learn what they really look like to users in production at every single moment.

The feedback loop becomes not only shorter but also more effective.

That’s it for now

So I hope this post got you thinking a little bit about what you’d like to achieve from your React design system, how to build it, and what’s important to keep track of overtime.

Bit gives you the power to build, release, organize and reuse components pretty much at any scale. Integrated with GitHub, it gives you control and power over the adoption and updates of components in your apps.

IMO It’s better to aspire to the democratization, or legalization if you will, of component development. That means encouraging all teams to build more reusable components and share them, which doesn’t have to be a lot of work with Bit, so to create an open discussion and standardize development.

But that’s really up to you. The most important thing is to tap into the speed and consistency that component can naturally provide us with, to provide our users with a great experience at every touchpoint, screen, and application.

--

--

I write code and words · Component-driven Software · Micro Frontends · Design Systems · Pizza 🍕 Building open source @ bit.dev