Accessibility and Headless UI Libraries - Adobe, Radix, Tailwind, MUI
Tags: frontend, a11y, webdev, react
Published: 2023-09-24 12:31:11

There are lot of UI libraries out there. Their goal is to speed up development by providing a design system and accessibility right out of the box. The design system comes with a tradeoff: it helps speed up development since the developers don’t need to create their own design system from scratch but it can be very restrictive with customization, which makes sites built with that library look similar to each other. It’s easy to identify which sites were built using Bootstraps, for example. This tradeoff is acceptable for developers who are not good at frontend and their sites’ features rely more on the backend.

Lately there has been more headless (i.e. ‘unstyled’) UI libraries that provides the accessibility with very minimal or no styling so devs can style it however they want. They provide features such as keyboard navigation, labels and attributes for screen readers, and focus management I have been perusing through some of them to incorporate into my own tech stack. Here are 4 libraries I looked at and my thoughts on them.

### [Tailwind](https://tailwindcss.com/) - [Headless UI](https://headlessui.com/)

![Tailwind Headless UI](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/38hzwuup2lacnyjt3lux.png)

- Component based - must be assembled in a certain way
- Incremental installation - can install install individual components instead of whole library
- Minimal - only 10 components at time of writing
- Tailwind has [Tailwind UI](https://tailwindui.com/), which is styled and fully customizable components but with no behavior

### [Radix UI](https://www.radix-ui.com/) - [Primitives](https://www.radix-ui.com/primitives)


![Radix UI Primitives](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/w5drw8sih0a6qh7diin3.png)

- Component based
- Incremental installation
- [Radix UI Themes](https://www.radix-ui.com/themes/docs/overview/getting-started) - minimally styled component library that is more of a superset of Primitives
- [ShadCN UI](https://ui.shadcn.com/) - 3rd party minimally styled component library built with Radix Primitives

### [Adobe](https://react-spectrum.adobe.com/) - [React ARIA](https://react-spectrum.adobe.com/react-aria/index.html)


![Adobe React ARIA](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/mkp9ibm2i6t4ixagm7xo.png)

- Provides hooks that returns props to be assigned to corresponding elements
- Documentation explains thoroughly how to use the hooks and the problems they solve
- Complete visibility and control over DOM structure
- State management decoupled from accessibility behavior - provided by [React Stately](https://react-spectrum.adobe.com/react-stately/index.html) hooks
- [React Spectrum](https://react-spectrum.adobe.com/react-spectrum/index.html) - component library built with React Aria and React Stately - documentation is confusing since there is a component section in React Aria that is nearly identical to React Spectrum
- [NextUI](https://nextui.org/) - 3rd party minimally styled component library built with React ARIA

### [Material](https://mui.com/) - [Base UI](https://mui.com/base-ui/)


![Material Base UI](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/1kxuhyql24nmdqdk55fr.png)

- Behavior and accessibility logic decoupled from Material UI
    - [Material UI](https://mui.com/material-ui/) - completely styled component library and follows [Google’s Material Design](https://m3.material.io/) design system
- Provides components like Tailwind and Radix
- Provides hooks like React Aria
- In beta - certain components are not complete or are experimental. Documentation is lacking, especially for hooks.

### My winner is React ARIA

My main problem with the other libraries is that I have to learn and think in their design system whereas with React ARIA, I’m thinking in native HTML.

For example, Radix’s Dialog component has 8 pieces: Root, Trigger, Portal, Overlay, Content, Title, Description, Close. It abstracts away the state management, logic and behavior, and HTML elements with these pieces that I have to assemble in a specific way. 


![Radix Dialog Component](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/wgnjb1ejngykwg0x4lzr.png)

And tweaking their behavior is exposed through certain props, not DOMAttribtues.


![Radix Dialog Content API](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/dkl4k7h9sr3acw9rl9mg.png)

With React ARIA, it’s a lot more code I have to write but working with semantic HTML and attributes makes me a better frontend engineer overall. With Radix, Tailwind, and Material, I only get better at using their library - knowing Dialog.Content must wrap around Dialog.Title and Dialog.Description does not transfer to anything else.  Additionally, I can intuit what the hooks do and see what their return values do. It reminds me of [React Hook Form](https://react-hook-form.com/) in this way.


![Adobe React ARIA Dialog](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/2h88ug8ai2j8kdevdbm6.png)

This is a lot more boilerplate than other libraries but it makes more natural sense to me.

As Tailwind makes you think in native CSS, I want to think in native HTML elements as much as possible.

Also, React ARIA documentation is superb - it lists all the features of the hooks and provides an anatomy diagram for each UI component.

![Adobe React Aria Anatomy Diagram](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/pxj03omje1gge26nwi80.png)

### Conclusion

Thinking about accessibility is hard. Implementing them is harder. Keeping up with guidelines and thinking of different devices take up lot of time and research. It requires lot of boilerplate code and is very easy to get wrong. That’s why I highly recommend using one of these libraries so people that require on assistive technology to browse the internet can do so easily on your site. If React ARIA seems too daunting, I recommend Radix Primitives since it has more features and documentation than Headless UI and Base UI.