This is an article with no idea what the title should be. Recently, I have investigated several excellent foreign open source component libraries. One of them is for the possibility of making basic component libraries as technical reserves, and the other is for jumping out of the “comfort zone” of domestic ANTD to see how foreign teams design component libraries.

Write the summary above

In order to make it easier for you to see the conclusion directly, I have moved the conclusion that was originally written at the end of the Intranet to the beginning. (Because from the Intranet, people don’t really want to see how I analyze the source code, just want to see the conclusion and what I do…)

Architecture implementation

In terms of code architecture, it can be roughly divided into the following categories:

  • Single package and multiple components: represented by ANTD, all components are of the same version;
  • Multi-package and multi-component: most foreign component libraries adopt this architecture. Each component wants to have a separate version, and the larger version is consistent.

Component granularity

In terms of component granularity, it can be roughly divided into the following categories:

  • Coarse granularity: Take ANTD Modal as an example, the custom rendering slots of such components are provided in the form of render props;
  • Fine granularity: Take most components of Radix-UI as an example, which are provided in the form of container + Children sub-components, advocating free combination of sub-components and high flexibility;
  • Finer granularity: Take the Example of the React-Spectrum component, which is provided not only as finer granularity at the UI layer, but also as logic hooks that break down finer granularity;

Style system design

In terms of style system design, it can be roughly divided into the following categories:

  • Style-free systems: Take RC and Headless UI as examples. These component libraries do not provide any style files and are implemented externally by the business side.
  • Have your own design language:
    • Style file: Take ANTD as an example. The styles of this component library are provided to components in the form of external style files. Users can externally cover styles by className and style.
    • StyledComponents: Take Chakra-UI as an example. The styles of this component library are built into components in the form of CSS in JS. Users can override the styles with custom themes and classNames.

I am of the view

In fact, when I looked at the implementation of Charkra-UI, I already had a basic component library design in mind.

First of all, from the perspective of style system, one of the purposes of redoing the component library is to avoid style pollution. So assuming that the design language has reached a unified premise, can we use CSS in JS to write our components in a radical way?

Next from the component structure, doing business component classmates may know, the business component is simply for a scenario based component combination, and often only to the base components in the process of combination of one or several functions (even when not meet very disgusting castration rewrite), then design basis component, Is it possible to design the already atomic base components more atomically? (such as those basic components that are currently available abroad)

So here’s the challenge:

  • Does more atomic design mean that users need to write more combinatorial logic in business code?
  • Does the adoption of incompatible ANTD API design mean that the users of the inventory business eat shit with compatible migration costs?
  • .

However, I have come up with a solution. Aiming at the above problems, can we design an adaptation layer to smooth the API differences between new components and ANTD? The adaptation layer encapsulates a layer of “skin” according to ANTD API to be used by existing businesses.

This is what our component library architecture looks like:

First of all, for the business component library, the bottom layer all uses the new basic component reconstruction, external does not change the original API. For the user of the business component library, there is no perception. For stock services, lock the ANTD API of the specified version and provide an adaptation layer compatible with ANTD API to smooth the transition. For incremental services, it is recommended to directly use the basic component library development. (Of course, I don’t know about the adaptation layer…)

(The above only represent my personal views…)

Component libraries are written at the back

Ant-Design

  • Warehouse: github.com/ant-design/…
  • Liverpoolfc.tv: ant. The design/index – cn
  • Architecture pattern: UI implementation (ANTD) + Headless implementation (RC)
    • UI implementation: single warehouse, single package, multiple components, each component based on headless components to do UI and event encapsulation, according to the specified version of the introduction of headless components;
    • Headless implementation: multi-warehouse, single package, single component, MutiRepo, no style, only dom and logic;

The biggest characteristic of ANTD is the separation of UI and DOM + logic. For custom rendered scenes in components, they mostly exist in the form of component + render props. Take Modal as an example:

On the style system, ANTD brings us the most common component with a style less file.

Chakra-ui

  • Warehouse: github.com/chakra-ui/c…
  • Liverpoolfc.tv: chakra-ui.com/
  • Architecture mode: single warehouse, multi-package, multi-component, MonoRepo;

In the implementation of Charkra-UI, there is no big difference between the basic UI components such as Input and Select and the conventional component library, and the components with more custom rendering scenes such as Modal, Tooltip and Popover are implemented in the form of plugable subcomponents. For example Modal:

In terms of implementation, Modal is not used as the UI component to actually mount DOM, but as the container layer to distribute props (implemented through context), and the part of actual RENDERING UI is carried by sub-components. Each sub-component as an entity receives props from the container layer to handle the corresponding UI presentation and events. Take ModalCloseButton as an example:

Charkra-ui is also interesting in the design of the style system. First, in the use of CSS, Charkra-UI adopts the StyledComponents based on @emotion/ Styled. In component implementation, StyledComponents are converted for each native DOM element or other component through the factory function under the @Chakra-UI /system subpackage. Take Input as an example:

For the basic style required by StyledComponents, Charkra-UI provides the theme subpackage as the default style theme of the component library. The theme package defines the style required by each component in the form of A JS object.

Then, in order for the default theme and custom theme to be injected into the component, Charkra-UI provides providers to inject theme styles

The use of StyleComponents also makes it impossible to properly override styles inside components externally, and Charkra-UI also gives us props for classnames.

MUI

  • Warehouse: github.com/mui/materia…
  • Liverpoolfc.tv: mui.com/zh/
  • Architecture mode: single warehouse, single package, multi-component;

The implementation of the component is similar to Charkra-UI, and the @emotion/ Styled StyledComponents are also used in the style system.

Headless-ui

  • Warehouse: github.com/tailwindlab…
  • Liverpoolfc.tv: headlessui. Dev /
  • Architecture mode: single warehouse, single package, multi-component;

Headless-ui is equivalent to antD-dependent React-Component (RC), which only cares about the DOM + logic implementation and leaves the UI style implementation to the user.

Radix-ui

  • Warehouse: github.com/radix-ui/pr…
  • Website: www.radix-ui.com/
  • Architecture mode: Single warehouse, multi-package, multi-component, MonoRepo;

Compared with CharKA-UI, the Radix- UI also adopts the form of plugable subcomponents in Select, the most basic data response component. In other words, the granularity of subcomponents is lighter and atomic in the implementation of Radix- UI. Take Select as an example:

In implementation, the container layer also uses the context to collect props, and the sub-component acts as the UI to respond to the props distributed by the container layer.

Similarly, radix-UI advocates style-free component libraries.

React-Spectrum

  • Warehouse: github.com/tailwindlab…
  • Liverpoolfc.tv: react-spectrum.adobe.com/index.html
  • Architecture mode: single warehouse, multi-package, multi-component, MonoRepo;

React-spectrum is implemented in three parts:

  • React-aria: Separate and provide hooks of reusable logic for component behavior, accessibility, internationalization, etc.
  • React-Stately: Split a portion of state used internally by components out of hooks for logical reuse;
  • React-spectrum: combine react-aria, react-Stately and DOM to implement basic components;

Compared with the above component library, React-Spectrum not only separates components from the UI side in the form of fine-grained sub-components, but also separates React-Aria and React-Spectrum from the logical side to provide hooks for logical decoupling. Similarly, decoupling of subcomponents is achieved through context.

On style systems, react-Spectrum does not recommend that users override style logic with classNames or styles, so we don’t see these two props on the component, React-spectrum believes that style overwriting can lead to unforeseen problems with subsequent component upgrades.