4

Building a React Design System for Adoption and Scale

 2 years ago
source link: https://blog.bitsrc.io/building-a-react-design-system-for-adoption-and-scale-1d34538619d1
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

Building a React Design System for Adoption and Scale

Achieve DS scale and adoption via independent components and a composable architecture — with examples.

Component libraries or design systems, enable cross-project code reuse and standardization of technology, design patterns, and “looks and feel”.

A good component library is a library that is highly composable. It provides components that can easily be used to compose a wide range of new compositions.

That, of course, is easier said than done. How should a component library be structured for it to provide the right assembly parts for all the organization's known and unknown use-cases?

“A good compromise is when both parties are dissatisfied”

— Larry David

The traditional top-bottom approach for a component library that prescribes the building blocks for all the organization’s frontend apps, most commonly in the form of a single package, usually ends up in some sort of a compromise that hurts all teams in an organization and often leads to poor adoption of that component library.

A good component library is not a library at all

The way to build a scalable and composable component library is not to build a library at all, but to collaborate on independent components, and share them in different remote scopes, grouped according to their purpose.

See the workspace for both scopes:

What are independent components?

An independent component is a component that is independently developed, versioned, and collaborated on. It can be a CSS module, a React UI component, a React hook, or any other type of JavaScript module. Each of these can be of different levels of complexity and concreteness.

An independent component contains the entire version history of its source code, configurations, and artifacts.

Independent components are developed and composed together in Bit workspaces. The components’ release versions are exported (pushed) to remote scopes where they’re made available to be used and collaborated on, in other Bit workspaces. Furthermore, since independent components also provide a standard Node package, they can be installed, using regular NPM clients, in non-Bit projects.

Bit is a tool that offers a monolith-like experience for the development of independent components. It provides intelligent component dependency management and a set of tools that greatly simplify the development and configuration of multiple independent components, all in the same workspace.

For component development, Bit provides the ‘compositions’ feature which can be used similarly to Storybook but also quite differently. ‘Compositions’ are mainly used to run manual and automated integration tests before such integrations are done by consumers of that component.

Bit also offers a built-in integration to Bit.dev, for component hosting and component-driven CI.

What are scopes?

Remote scopes are not monolithic libraries. They serve as a way to organize individual components into separate categories, each with a different set of members and permission levels. Remote scopes are hosted on servers running Bit (e.g, bit.dev)

Independent components imported from multiple scopes and exported back with a new version

Using independent components the right way

This process of building, sharing, and collaborating on independent components results in an ever-expanding network of components that provide just the right level of concreteness, complexity, and standardization for all frontend applications.

Independent components enable an organization to build its collection of components using a mixture of top-bottom and bottom-up approaches, where some components are built using the organization’s infra team, and some are developed and collaborated on by other teams, working on specific features or sub-brands. This is done using a triad of base-UI, brand-specific, and feature-specific scope types.

Independent components hosted on 3 scope types: Base-UI, Feature, and Brands

Base-UI scope

An organization's Base-UI scope, maintained by the infra/design team, hosts the organization’s commonly used UI components, React hooks, “styling components” (CSS modules, fonts, icons, etc.), and a theme provider.

Base-UI scopes in different organizations vary in the level of customizability they allow by offering a set of components that range from being slightly opinionated to highly opinionated.

A strict Base-UI scope

A strict Base-UI scope is built as a highly opinionated set of components that enforce a strict set of styling rules. This is done by offering a limited “styling API” that restricts the range of possible designs. In that case, the scope will consist of:

  • A “fuller” set of styling components
  • Heavily styled UI components
  • A theme provider with a highly opinionated theme scheme (i.e, how themes in an organization should be structured).

A soft Base-UI scope

A soft Base-UI scope sets almost no restrictions to styling. In that case, the scope will consist of:

  • A limited set of styling components
  • Un-styled or slightly styled UI components
  • A generic theme provider

Example: A soft Base-UI scope

As you would expect, the scope shown below offers almost no styling and a very generic theme provider that is only slightly opinionated as to how themes should be structured in that organization.

The soft Base-UI scope theme provider:

The soft Base-UI theme-provider using React w/ TypeScript and SCSS modules

Brand-specific scopes

Brand-specific scopes are scopes with highly opinionated UI components and theme providers. These sorts of scopes are maintained by teams in an organization, working under one of the organization’s brands or set of products. A brand-specific scope will override parts of the theme provided by the Base-UI scope. It may also include components composed out of other components offered by feature-specific scopes and even its own unique components.

A brand-specific scope will consist of all or any of the following:

  • Styling components
  • A customized (brand-specific) theme provider that extends and/or overrides the theme provider offered by the Base-UI scope.
  • Additional UI components that are unique to this brand.

The brand-specific scope will consist of a [somewhat] finite number of styling components, defining its look and feel, with an endless and ever-growing number of UI components.

Example: A brand scope — “design”

The design scope composes new components out of the Base-UI scope. Components that are simply themed will not be part of this brand scope but will be imported directly from the Base-UI to minimize the number of components an organization uses and have each component maintained by its “real owners” (in the case of an unopinionated Base UI, that rarely happens).

Below is the brand scope’s theme provider which extends the theme-provider hosted in the Base-UI scope.

The brand scope’s theme provider which extends the one provider by the Base-UI scopeThe dependency graph of the “design” theme component which extends Base-UI’s theme-provider

Feature-specific scopes

Feature-specific scopes are scopes that host UI and non-UI components with no specific theming. These components serve a specific purpose, a feature.

UI components will be composed, as much as possible, out of components stored in the organization’s Base-UI scope.

Handling dependencies between independent components

Independent components form a network of dependencies between themselves. Updates made to one independent component will propagate to all independent components affected by it. This will trigger tests, builds and new version releases, in each of these components.

Think of this network of distributed independent components as one endless monorepo, where you’re able to enjoy all the benefits of simple, small decoupled codebases, with those of a single repository.

This component-driven CI encourages teams to compose (and not reinvent) using components authored and maintained by other teams. It provides each team with autonomy over its set of components but does not exempt it from being held responsible for the effects it may have on other teams and products.

So, for example, an update to components in the Base-UI scope will propagate to all dependent components in the various brand scopes and feature scopes. This will provide the infra team with a clear understanding of the effects these changes have on the entire organization. The same is true, of course, for all other scopes — feature scopes, and brand scopes.

Conclusion

Independent components and Bit redefine the way we think of design systems. A design system is no longer a constant set of components, but a protocol for structuring and styling components. This protocol picks up new nuances as it transverses through the organization's various sub-brands and products.

Try it out for yourself ->


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK