Create a Modular React Component Library

A guide to building a React component library that scales

Eden Ella
Bits and Pieces

--

Design systems/UI libraries used to be a luxury enjoyed exclusively by large enterprises, but in recent years, due to the advent of new technologies, we've seen that changed quite drastically. Design systems have now become a tool used by organizations of all scales, from single freelance developers and small dev teams, all the way to large and mature enterprises.

Why Build a UI Libray/Design System?

UI libraries affect both ends of the development process: the coding and the final product.

UI libraries speed up development

  • UI libraries maximize code reuse and speed up development.
    They do so by making components available to all projects in and across repositories. They also make components easier to find and understand (as they’re documented and indexed in one central location) — after all, reusable code no one knows about isn’t that useful.
  • UI libraries make codebases easier to scale and maintain.
    A DRY codebase means fewer lines and files to go through. Fewer duplications also mean better predictability to changes in code (it may be argued that sharing code across projects makes predicting outcomes more challenging, but as you’ll see in this post, it’s only a matter of using the right tools).
  • Lastly, code that is written for reuse is better code. It’s documented, testable, and pure (return values for each argument remain consistent with zero changes to their environment). Better code is more maintainable code.

UI libraries help deliver a better user experience

  • A limited set of UI components means your users spend less time learning your product and more time enjoying it.
  • Consistency in style and functionality makes it much easier for users to predict the outcomes of actions performed on your app, minimizing the chance for confusion and the frustration that follows it.

What’s a Modular Library? Why Are They Important?

A standard library is a monolith. It’s built and maintained as a single object — a single repository, a single build setup, and, usually, a single package.

Components are organized by ownership or business functionality

A modular library, or a collection, is a scope that serves only as a way to organize components by ownership or business functionality (there are currently no other implementations of modular libraries that I’m aware of other than Bit.dev, but I’m sure there will be).

Each component is versioned and built as independent code

Components published to a collection are versioned and built independently, which means they can be harvested from any codebase/repository. That gives us the freedom to publish components whenever we like and from whatever project we choose. It doesn’t have to be a full-on component-library project.

No pesky meaningless updates

Consumers of shared components only have to deal with version updates that are relevant to what they actually use as they consume each component directly and not as part of a larger project (e.g., a library).

Some tools you could use:

Building a UI Library With Bit and Bit.dev

What is Bit/Bit.dev?

Bit.dev is a component hub (a private registry and a documentation site). It’s where you host, document, and manage reusable components from your different projects. It works perfectly with Bit, an open-source tool that handles component isolation and publishing (when using Bit.dev, components are published to Bit’s registry).

Example: Browsing through component collections in Bit.dev

As mentioned earlier, components can be published to a collection from any project at all. To demonstrate that, I’ll harvest and publish components from a demo React with TS app.

https://github.com/giteden/react-ts-demo-app

1. Create a component collection in Bit.dev.

2. Install Bit globally (npm/Yarn).

$ yarn global add bit-bin

3. Log into your account.

$ bit login

4. Initialize a workspace in the project’s directory.

// To follow along with my demo app, clone and install it$ git clone https://github.com/giteden/react-ts-demo-app.git
$ cd react-ts-demo-app
$ yarn
// initialize a workspace (in your project's directory)$ bit init --package-manager yarn

Note: Notice how a new .bitmap file has been added to your directory, and a bit section has been added to your package.json.

5. Track all components. In my case, components are located in the components directory (for example, src/components/button/index.js):

$ bit add src/components/*

Note: Placing all files under the same directory is yet another way to make your code more comprehensible to other developers (maintainers and consumers of your reusable components). It’s much easier to understand how different files relate to each other when they’re grouped under the same directory. Moreover, it’s a way to make your reusable component more mobile and autonomous.

6. Configure a compiler to make the components usable in other environments with different setups:

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

Note: For other compilers, check out Bit’s ENVs collection or learn how to build your own.

7. Tag the components to build them in isolation (and lock changes):

$ bit tag --all 1.0.0

Note: Bit tracks your component dependencies by itself and doesn’t require manual configuration. Having said that, it’s good practice to check for unresolved dependency issues using $ bit status .

8. Export all tracked components (push them to the shared collection):

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

The components are now shared and publicly available 👍

If you followed along, go to bit.dev/<user-name>/<collection-name> to see them rendered in Bit’s playground. Otherwise, you can check out my collection here:

A demo React with TS collection

Documenting Components

The process of documentation starts at writing components in your local dev environment and ends at writing examples in the component page on Bit.dev.

When using React with TypeScript, most of the job is done for us. Bit extracts props and types, forms documentation, and displays it on the component page (on Bit.dev). As wonderful as it is, it’s always good to enrich your autogenerated documentation with JSDocs descriptions.

Documentation on the component page

Note: When using react-docgen/Bit.dev to autogenerate docs for your reusable components, the prop’s type/interface should be defined both as a generic of React.FC<T> and (directly) as the function’s arguments type (otherwise, your props won’t appear in the generated docs).

Writing Examples in Bit’s Playground

After exporting components, it’s best to complete the documentation process by providing an example (on the component page).

Examples enable components to render in Bit’s playground (a component that doesn’t receive its required props won’t be able to render) and guide consumers of components on how/how best to use them.

A component rendered in Bit’s playground

--

--