Components vs. Primitives

Encapsulate the expected functional component UX without styles.


In our current codebase, there are multiple occurrences where our design system components have their defined style altered via overrides. It might seem small, but it eventually becomes death by a thousand cuts. We are giving our users a shifting interface to interact with; they can’t be confident about what is being presented if things are inconsistent across the platform.

For this reason, we should separate those components that adhere to a defined style implementation of the design system, which we will call UI components and components that encapsulate the expected functionality in that they can be used as a base to add style to make a complete UI experience, which we will call primitives.

UI components should follow all aspects of the design system and uses design system tokens as their guide for stylistic choices. To better follow this, they should only expose the ability to change their style in a defined manner instead of exposing the ability to add class names or alter individual CSS properties.

Primitives, on the other, should follow the expected functional UX patterns of the design system but have no defined styles. They should be used scaffolding to build UI on top of and expose the ability to change their style via className so things like styled-components styled function can use them.

An example of how this is implemented is with the new Button Primitive.