November 06, 2021

How I Would Use a UI Library

edit

I’ve recently been working on a project that uses Chakra UI. I’ve enjoyed using it, for the most part. I’ve had a few moments that made me go, “Do I want to build my own UI library?” and then immediately snuffed that thought out of existence. Ain’t nobody got time for that.

That said, working with Chakra has made me think of an architectural pattern I would be very tempted to employ if I was building the project’s design system from the ground up and knew it was going to be a long-living project.

I’ll get right to the chase. Here’s my idea: for every UI component you’re using in the library, create a facade of your own and consume the facade throughout your app. Do not consume the library directly in your features and other component compositions. If I implemented this, I would go so far as to create an ESLint rule that enforced this pattern.

Before I explain all the reasons why, here’s a simple facade example. You’ll probably think I’m nuts.

import React from 'react'
import { Button as ChakraButton } from '@chakra-ui/react'

export default function Button(props) {
  return <ChakraButton {...props} />
}

I can hear you saying, “Ok, why in the hell would you recommend this, Kyle?” The answer is simple. This creates a lot of flexibility and likely will save me future pain when requirements change at a very low cost now.

”YAGNI! YAGNI! You’re Not Gonna Need It!” I hear you scream. Maybe you’re right. But I’ve never worked in a project that lasted a decent amount of time without some upheaval to the UI components.

Here is a short, non-exhaustive list of things you can do easily with this one layer of indirection:

Swap out the library

If you need/want to try a different component library, you can swap out the implementation under the hood without any change to consumers of your UI components (your other developers/teammates). You can make this change component by component. You don’t have to do a wholesale, sweeping change.

Add or Restrict props

If you want to add props that aren’t on the underlying component, you can do so and map them to some functionality. Or you can create useful aliases to props if they would benefit your team.

Also, you can restrict which props can be used in the underlying UI library. Maybe there’s some weird prop you just really want to avoid using. All easily done with a layer of indirection.

Rename/Remap props

If you ever need to rename/remap a prop because of an update to the component library, you can do so without needing to change every instance of that component throughout your app. No codemods. Just one simple change.

How I would implement this

I would start by making two directories: features and ui. I may need to add this to my React project structure post.

Then, every UI component in my app gets a facade in the ui directory. No exceptions.

Finally, I would implement an ESLint rule preventing the import of any third party UI library into the features directory. Features can only import components from other features or the ui directory.

Downsides

I can think of one downside to this approach. Documentation.

Consuming the UI library directly in your app means you rely solely on the documentation of the UI library. If you use the facade pattern, you have to indicate to your consumers where to find the information they need. This means pointing to the documentation of the implementation details, or writing your own docs to cover them. If you end up adding or restricting props, you’re going to need to document how the component is used anyways.

Summary

Give yourself some future flexibility by using a facade between the UI library you’re using and your features. The extra work could save you a lot of pain down the line.


Finished reading?
Liked the post? Give the author a dopamine boost with a few "beard strokes". Click the beard up to 50 times to show your appreciation.

Kyle Shevlin's face, which is mostly a beard with eyes
Kyle Shevlin is a software engineer who specializes in JavaScript, TypeScript, React and frontend web development.
Agathist
Good software by good people.
Visit https://agath.ist to learn more
Sign up for my newsletter
Let's chat some more about TypeScript, React, and frontend web development. Unsubscribe at any time.
Logo for Array.reduce()
Array.reduce()
Check out my courses!
If you enjoy my posts, you might enjoy my courses, too. Click the button to view the course or go to Courses for more information.