5 tips to build a better React component

Lior Heber
skai engineering blog
4 min readJan 11, 2022

--

If you are maintaining your own React components library, you probably know very well that components evolve and grow. Because requirements can often change over time, your components need to be flexible enough to adapt to new needs.

Today I’d like to share five best practices we follow at Skai that have worked well for us when developing React components.

1. Stick to the native API

Let’s imagine we are developing a dropdown menu. The dropdown receives an array of options and a selectedValue prop. Additionally, we add a callback prop for onSelectValue.

While on the surface this would work, there are two inherent issues with using custom props versus standard ones:

  1. Standards exist to help everyone. Other developers are unfamiliar with your naming decisions and will rely on your documentation. While you would want to ensure your component is properly documented, sticking to the standard HTML API — and React’s synthetic events — ensures that your component behaves in a predictable way for anyone who decides to use it without having to check the documentation.
  2. Keeping within standards may be useful later. It’s not only your peers who would benefit from using the standard APIs, but other components that may rely on your component would benefit from it too. Consider our dropdown. If we were to use it with a library like react-hooks-form, a special wiring would be required every time we would integrate our component with it.

Instead of using overly specific props, align them to already agreed upon names. In this case, value and onChange or onSelect, just as they would be defined if you were using HTML and vanilla Javascript.

You now ensure that there’s a high probability that your component plays well with anything that needs to use it, and that your users will be immediately familiar with your props.

  • Please note that this is not necessarily how we would implement a dropdown component.

2. Expose the className and style props

So, you’ve built a very useful component, pushed it to the common library or even open sourced it. Make sure to provide your users the flexibility to customize your component by exposing the className and style props.

I cannot stress enough how important this can be.

Different projects may implement styling differently. Some use regular css, others might use css modules, Styled Components or TailwindCSS and some might need access to your inline style. Providing these two props to the external world enables anyone to use virtually any styling technique that works for them with minimal effort on your side.

Let’s take a look at how I can customize my component with popular styling libraries using the same className prop:

3. Prefer composition over configuration

Returning to our Dropdown example, too often do I see props like searchable, withIcons, multiSelection, withClear, etc.:

When I discuss these props with a developer, they explain that providing these very specific props to the user improves the simplicity of the component. I’d argue, however, that, as the project progresses, these props can over-complicate your component to the point where it’s hard to maintain and use.

One flag prop doesn’t seem harmful — and sometimes they are even necessary (e.g. for states like disabled) — but too many flags lead to overly-complicated documentation, and even worse, a very complicated codebase that requires specific handling of every such flag. Instead, I would like to suggest enabling features by letting your users compose them in.

Consider this example:

You might argue now that this API really complicates using the component if I need to recreate this code every time. Read on to see how we tackle that argument.

4. Provide building blocks

In the previous section, we provided a route to support complex customization to our dropdown without changing our component to support them. We gave our users a choice. However, in doing so, we really complicated the lives of our standard user that doesn’t need customization but just wants to be able to use the dropdown as a regular dropdown and as a multi selection dropdown.

To support the common use case, we provide building blocks that ensure that copying common compositions across our projects is unneeded.

Now, most of our users can easily use our pre-built building blocks, while someone that needs a more specialized component can use their own custom implementation along with the existing building blocks.

5. Extend an existing project

You were assigned the task of creating a toggle component. The native equivalent is a checkbox, but the user experience and design of the two components is quite different. It seems like an easy enough task to just write the component from scratch to your requirements. I would argue you should first use your favorite search engine and see what’s out there.

TIP: Look for an existing solution.

Good solutions are built on the foundation of knowledge and effort. While you might be very knowledgeable and willing to put in the effort to build the best component, there’s still a very good chance that a group of people maintaining a solution — improving it over time, guided by the experience of a wider range of users — would provide a solution that tackles even the smallest issues you didn’t even consider.

If there’s a popular, well-maintained solution out there that solves the problem you’re facing, I highly recommend you explore that option. In the best case scenario, you are able to offload a lot of the responsibility of the component to a project that is focused on solving the issues that component entails. At worst, you will have a very good pointer to how to build a better component.

The bottom line is that unless your sole focus is to build that component and you are about to put hundreds of hours into your component, it most likely will not yield a better result than a project in which other developers spent hundreds of work hours to perfect.

--

--