Articles
November 3, 2024

Component Libraries - Part 1

Working With React Component Libraries for Interactive Controls

Component Libraries - Part 1

Sleek v2.0 public release is here

Lorem ipsum dolor sit amet, consectetur adipiscing elit lobortis arcu enim urna adipiscing praesent velit viverra sit semper lorem eu cursus vel hendrerit elementum morbi curabitur etiam nibh justo, lorem aliquet donec sed sit mi at ante massa mattis.

  1. Neque sodales ut etiam sit amet nisl purus non tellus orci ac auctor
  2. Adipiscing elit ut aliquam purus sit amet viverra suspendisse potent i
  3. Mauris commodo quis imperdiet massa tincidunt nunc pulvinar
  4. Adipiscing elit ut aliquam purus sit amet viverra suspendisse potenti

What has changed in our latest release?

Lorem ipsum dolor sit amet, consectetur adipiscing elit ut aliquam, purus sit amet luctus venenatis, lectus magna fringilla urna, porttitor rhoncus dolor purus non enim praesent elementum facilisis leo, vel fringilla est ullamcorper eget nulla facilisi etiam dignissim diam quis enim lobortis scelerisque fermentum dui faucibus in ornare quam viverra orci sagittis eu volutpat odio facilisis mauris sit amet massa vitae tortor condimentum lacinia quis vel eros donec ac odio tempor orci dapibus ultrices in iaculis nunc sed augue lacus

All new features available for all public channel users

At risus viverra adipiscing at in tellus integer feugiat nisl pretium fusce id velit ut tortor sagittis orci a scelerisque purus semper eget at lectus urna duis convallis. porta nibh venenatis cras sed felis eget neque laoreet libero id faucibus nisl donec pretium vulputate sapien nec sagittis aliquam nunc lobortis mattis aliquam faucibus purus in.

  • Neque sodales ut etiam sit amet nisl purus non tellus orci ac auctor
  • Adipiscing elit ut aliquam purus sit amet viverra suspendisse potenti
  • Mauris commodo quis imperdiet massa tincidunt nunc pulvinar
  • Adipiscing elit ut aliquam purus sit amet viverra suspendisse potenti
Coding collaboration with over 200 users at once

Nisi quis eleifend quam adipiscing vitae aliquet bibendum enim facilisis gravida neque. Velit euismod in pellentesque massa placerat volutpat lacus laoreet non curabitur gravida odio aenean sed adipiscing diam donec adipiscing tristique risus. amet est placerat in egestas erat imperdiet sed euismod nisi.

“Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum”
Real-time code save every 0.1 seconds

Eget lorem dolor sed viverra ipsum nunc aliquet bibendum felis donec et odio pellentesque diam volutpat commodo sed egestas aliquam sem fringilla ut morbi tincidunt augue interdum velit euismod eu tincidunt tortor aliquam nulla facilisi aenean sed adipiscing diam donec adipiscing ut lectus arcu bibendum at varius vel pharetra nibh venenatis cras sed felis eget dolor cosnectur drolo.

Why do we need a component library in the first place?

Developers who have strong proficiency in the fundamentals of HTML and CSS might feel that importing a component library is redundant, or might think it's only needed for achieving a decent appearance when you can't afford a UI designer and a frontend dev to implement the design. After all, it's not too hard to put together elements in a flexbox or to apply colors, padding and margin consistently.

However, when you actually try to craft your components from the native building blocks of the web, you will probably run into various issues. You might be fine as long as you only deal with simple layout and typography, but once you get into more complex elements, especially elements that have some behavior – like form controls or toast notifications, you'll easily run into issues of broken functionality, accessibility concerns and unhandled edge cases.

For example, a toast notification sounds like a simple case – it appears in response to some event and goes away after a predefined timeout period. But there's actually a lot of logic there:

  • You probably want the notification to stay when the user hovers over it with the mouse, as well as when the user navigates to it with the keyboard, especially if there's some button or link on it.
  • You probably want it to go away once the user moves the mouse away from it.
  • You want smooth in- and out- transitions, so it must not unmount until the out-transition ends.
  • You want to handle a queue when there are multiple notifications in a short period, so that the order they appear makes sense, as well as the time spacing between them.
  • You want the content to be announced by screen readers, and the timing of the announcement should match the message's priority (urgent or not urgent).
  • You might want to limit the size of the notification card, but add a "see more" button when the content is too long.
  • And so on.

Handling these features is definitely doable, but you don't want to spend a lot of time on that. You want to focus on your project, on your product, rather than hunting edge cases of common UI elements. That's where component libraries come to our aid. They provide us these features "out of the box" or offer the means to easily implement them.

But that's just one aspect of the equation. Once you decide to use a component library, you still need to decide which one, and the choice doesn’t come without cost. The more opinionated the library is, the more it provides you production-ready stuff – the harder it is to customize it – to override specific styles or specific behavior. You want your component library to assist you, not to be an enemy you're struggling to fight against.

It can be said that component libraries provide up to three layers of predefined building blocks:

  1. Functionality and Accessibility – This is the base layer: The checkbox responds to user clicks as well as to the keyboard; it becomes unresponsive when disabled; proper events are fired; the combo-box inner list is only rendered when the element is in focus; etc. This layer handles the complicated UI logic, and if it's properly built, you're rarely expected to want to override its behavior.
  2. General Look – This layer provides a clean and sensible look to the element – proper alignment, consistency between different parts, standard visual cues like the "√" icon in a checkbox, etc. This layer is where different libraries may differ significantly – some will be more opinionated, allowing little space for customization, while others may be more open to overrides, perhaps at the cost of simplicity.
  3. Theming and Branding – This layer provides the fine-grained look – fonts, colors, sizes, etc. While the library defaults might be fine for a personal project or a POC, libraries are usually expected to provide means to customize these aspects, so that every product can have its own unique appearance and branding.

In this series of articles we'll first see an example of building something with no component library. Then we’ll check the Radix-UI library, which provides the first layer of the three – the functionality layer – while leaving the whole job of styling to the developer. Finally, we'll see two different higher-level libraries with different approaches, both built on top of Radix’s primitives: The first is Radix Themes – coming from the same creators, and the second is shadcn – a no-installation component repository.

Let’s build an app

To understand the place of component libraries better, let’s craft a tiny React app that shows the capital cities of different countries. It’s a very simple one – basically just a dropdown list of countries to choose from and a single sentence informing what the capital city of that country is. Here’s the full code of the App component:

1import { useState } from "react"
2import SelectCountry from "./components/SelectCountry";
3import CountryCapital from "./components/CountryCapital";
4import "./App.css";
5
6const capitals = {
7  Britain: "London",
8  France: "Paris",
9  Israel: "Jerusalem",
10}
11
12function App() {
13  const [country, setCountry] = useState("Britain");
14  const capital = capitals[country];
15
16  return (
17    <div className="app-container">
18      <SelectCountry
19        countries={Object.keys(capitals)}
20        onCountrySelected={setCountry}
21      />
22      <CountryCapital
23        country={country}
24        capital={capital}
25      />
26    </div>
27  )
28}
29
30export default App

Our app has a state (the chosen country), a data object mapping between each country and its capital, and two components: <SelectCountry> for the user to choose a country out of the list, and <CountryCapital> to display the capital city of the chosen country.

Version 1: Using native HTML controls

Of course, for our app to work, we need to actually implement these two components. There is already a <select> control as a native HTML element, so let’s just use that, without any component library:

1export default function SelectCountry({ countries, onCountrySelected }) {
2  return (
3    <label>
4      Choose country:
5      <select
6        onChange={(event) => {
7          onCountrySelected(event.target.value);
8        }}
9      >
10        {countries.map((country) => (
11          <option key={country} value={country}>
12            {country}
13          </option>
14        ))}
15      </select>
16    </label>
17  );
18}

1export default function CountryCapital({ country, capital }) {
2  return (
3    <p>
4      The capital city of <strong>{country}</strong> is <strong>{capital}</strong>
5    </p>
6  )
7}

One of the nice things about using native HTML controls is that even without adding any CSS at all, it “just works”. Sure, it doesn’t look very aesthetic, but nothing is broken.

Closed
Open

Splashing some CSS in, we can turn that into a nice-looking widget:

Closed
Open

That seems good! We might still want to adjust the colors and the fonts, perhaps add some decoration, display the country flag, etc - none of this is complicated to customize.

Well… none except that dropdown box itself..

The native <select> element rendered by the browser offers few styling options, and we can apply almost no styling to the options in the list. Doing something “advanced” like adding a flag icon next to each country name or marking the currently selected item is probably entirely out of the question.

If we do want something that looks better, we might be tempted to hide the native control entirely and display something of our own. But then we’ll lose the built-in semantics and easily run into issues of accessibility and functionality. We need some solid ground for it, and that’s what we’ll look into in the next article of this series.

About the author

Software developer, expertise at TypeScript, React and Node.js

Subscribe to our newsletter

Thanks for subscribing to our newsletter
Oops! Something went wrong while submitting the form.
Subscribe To Our Newsletter - Sleek X Webflow Template