Dumont Digital logo

Radix Themes vs Primitives

Published

The recent release of Radix Themes had me a bit perplexed. I felt that some questions weren’t answered:

How does this solution stack up against other UI component libraries? What level of customization should we expect? How does it set itself apart in this crowded market of React component libraries?

So I looked into it.

Background

Radix Primitives, a library of accessible, unstyled React components, was initially launched towards the end of 2020. You can adopt these components independently and style them with any method: CSS classes, Tailwind, CSS-in-JS, etc.

I suggest reading the Introduction page of their documentation if you’re unfamiliar with headless component libraries.

In brief, these collections of components implement common web UI patterns, which are not provided by the HTML spec, but are well documented and understood by the web development community.

There are several libraries in the React ecosystem that offer these benefits.

There’s React Aria, for example, which emphasizes accessibility by providing hooks and components for the aforementioned patterns, and Headless UI, which is geared towards compatibility with Tailwind CSS.

Other frameworks also feature similar libraries.

How to use unstyled components

Let’s delve into how it works in practice by examining some code adapted from the Radix Primitives docs:

import * as React from 'react';
import * as Popover from '@radix-ui/react-popover';
import './styles.css';

const PopoverDemo = ({ triggerContent, popoverContent }) => (
  <Popover.Root>
    <Popover.Trigger className="PopoverTrigger">
      {triggerContent}
    </Popover.Trigger>
    <Popover.Portal>
      <Popover.Content className="PopoverContent">
        {popoverContent}
        <Popover.Arrow className="PopoverArrow" />
      </Popover.Content>
    </Popover.Portal>
  </Popover.Root>
);

export default PopoverDemo;

It’s quite intuitive:

  1. Import the building blocks of the pattern you want to implement, which, in this case, are exported as a compound component.
  2. Construct the structure using the component’s various parts.
  3. Add styles, either with className as shown above, or with your preferred CSS solution.

An unstyled component library such as Radix Primitives lets you skim over the intricacies of accessibility and focus on your application’s unique aspects, instead of reproducing patterns that should really be part of the web platform.

All things considered, it’s an excellent choice for developers looking to implement their own design system.

Radix Themes

Moving on to Themes, an intriguing release built atop Radix Primitives.

It’s slightly challenging to define and pinpoint its position in the component library market.

I’d be inclined to label it as a theming library for Primitives, but it seems to be more constrained than that. I’d like to draw a parallel to Theme UI, but the latter offers full customization, while Themes restrict you to the following:

If you’re expected to accept the look and feel of the components provided, in order to simplify development of simple pages and prototypes, I fear we’ll again be submerged with undifferentiated designs reminiscent of Tailwind UI templates.

It could lead to a surge of identical landing pages, with minor differences in color schemes.

What if you want to build an entirely different UI using the Themes components? Would it make sense, or should you instead use Primitives directly?

Here’s what one of the Radix UI cofounders had to say about the difference between themes and primitives:

And here’s what the announcement stated about styles:

So, it’s not a styling solution, but you should be able to modify the components to fit your requirements.

Radix Themes in practice

After some experimentation in a quickly scaffolded React app, here’s my conclusion: while styling is feasible, not all components make it straightforward.

For instance, changing the border color of the Card component demands either overwriting or disabling box-shadow on an ::after pseudo-element using an !important declaration, then setting a border on its child div rather than the component itself.

You’ll need to put in some effort and dig into the source code or devtools to understand where and how the built-in styles are applied.

So, it’s definitely not a styling solution for Radix Primitives, which I would have loved to see. Instead, it’s a themeable component library with a rather limited scope of customization options.

Conclusion

For a custom design, better use Primitives directly, along with a token-based styling solution of your choice.

If, on the other hand, you value speed more than a differentiated look, recognizing that moving to your own design system later would require a rewrite to Primitives, Radix Themes might be a good pick.

As with all pre-styled component libraries, you’re gaining speed now in exchange of a larger maintenance burden later, should you decide to give your project its own visual identity.

The key is in understanding those trade-offs.


© 2024 freddydumont