React spread attributes — Don’t overuse them.

Or: How reducing flexibility can make your components consistent, and your dev team happy?

Yuval Bar Levi
6 min readJun 22, 2021

This is a (very) opinionated post, but you’ve probably inferred that from the title already. You won't learn about any cool feature or fresh js library after reading it, but hopefully, it might help you write more maintainable components and apps. So, what I’m aiming at, and why?

In the React Documentation you can see some simple example for Spread Attributes usage:

The Docs comes with the following suggestion/warning:

Spread attributes can be useful but they also make it easy to pass unnecessary props to components that don’t care about them or to pass invalid HTML attributes to the DOM. We recommend using this syntax sparingly.

It is important to clarify that the ability to pass props as a spread attribute is both useful and important, and it can be great when properly used. Yet, it’s a tool that can be easily abused. Let’s see this in an example using a very basic component — A button.

Our primary button component is wrapping Material-UI’s “Button” component internally, setting color with “primary” value (Duh!), and passing down all props.

Material-UI is a very popular UI library, created specifically for React. Its basic component supports props like color, size, variant, etc., which are described in the docs. In case you’re not familiar with it — just think about a Button component with the following API:

Using 3rd party libraries is a common cause for passing props as spread attributes. This looks easy and flexible. Of course, the same principle applies to any generic component — 3rd party or not.

At first, this decision may look reasonable, especially at the early stages of a project. Yet, it might do more harm than good in the long run. Let's go through some potential issues here, from least to worst.

It is less informative

we do not know what the actual prop being passed without digging into other (sometimes multiple) files. As our app grows, more components will use our button, and so, our once-simple component button might go cryptic. Some will use it like:

Yet it is very possible to use it like this

Hold on! variant="contained"? disableEleveation? size? What are these?
Those props were not described by our code anywhere!

Yes, we can dig into Material-UI’s wonderful documentation and dig into it every time we see a non-familiar prop. We can even use Material-UI typing — If we use typescript in our react project. And while both good documentation and a good typing system are important, we can save this trouble in the first place by using only hand-picked props, which will be reflected in our code.

Using specific props will make the code more predictable and readable

It’s too flexible

As developers, we love flexible, extensible, and generic code. The obvious reason is — we want our code to last, and save ourselves work in days to come. A flexible code covers more use-cases and therefore requires fewer changes in the unknown, ever-changing future. Isn’t that so?

This common tendency for flexibility can be disadvantageous in some cases. Think about javascript — one of the most flexible script languages. This flexibility is, arguably, one of many reasons it got so popular. However, the lack of typing may be a huge drawback as your program grows. Surely any JS programmer remembers having hard Debug time, just to finally find an argument passed with String value instead of Number, or something silly as such. From that pain — Typescript was born.

Flexibility can be graceful. Yet sometimes, It can be too much.

The same goes for small, “Atomic” components, which tend to be used widely in a project.
A basic component like a button should not be too flexible. Even a large web application should have a very limited number of different button types.
In other words — buttons should not be flexible at all. They should be very specific components!

Back to our PrimayButton. There is no real reason to expose all 14 props of Material-UI’s Button if all you really need are 3 of them. In the case of a button, it is better to expose the minimal number of props, even at the cost of possible future changes, since exposing too much will make it easier to make mistakes and use props wrongly. When I say Wrongly, I mean — in a manner that will make the app less consistent.
This leads us to the next point.

It makes the system less consistent

sometimes we need to expose 1 or 2 props, but ending up exposing other props as well. The problem is, we can create more variants of a component that we actually need, without noticing it. Let’s think about the following variation for our PrimayButton.

How many Variants we can create using PrimayButton2?
If you’ll check the docs, you’ll see size property may accept 3 possible values: 'large', 'medium' and'small' . Therefore when using PrimayButton2 we can create 3 variants of it at most:

How many variants it is possible to create using our first version — the notoriously flexible PrimayButton?
Since it accepts 14 different types of props, each can have multiple values, that end up to… well, a lot.

When creating a variant of a button is simple as providing a prop, it is easy to miss it when we create a new button, different than all the other ones we already have.

This is problematic especially for agile, fast-moving development teams when a proper design system is missing. This is a common case for (but not limited to) startup companies in the early stages. Without a proper design system, we might create a different variant of our button without meaning to. For example, our basic button supports multiple sizes for a button. While it is useful for some apps, it is not required for others.

On an agile team with no design system, such property is not only un-required but also a pitfall — we might select the wrong size (due to design error, missing design, etc.) without any technical means which prevents us to do so.

Creating concrete, inflexible components will help us create a design system de-facto, even if non-provided. It would not prevent us from creating another specific component (in our case — another button), but it would make such a decision much more obvious and easy to spot since it requires a more significant change.

So, are all spread attributes bad?

Not at all. It is OK to spread attributes, as long as it does not create unwanted possible component variants. simply put — avoid creating too-flexible components without good reason.

The most common usage for proper usage of spread attributes is when writing custom hooks. You’re probably familiar with the useFormInput custom hook example, firstly introduced on Dan Abramov’s Hooks Intro back in 2018:

Our input consume the custom hook value and handler properties using spread attributes — <input {...name}/> .

Other good use may be of the kind specified in the React docs, Which we saw at the beginning of this post:

Even without seeing the actual implementation of <Greeting> Component, we can see the spread attributes here do not affect the flexibility of <Greeting>, but rather used here for convenience.

Summary

  • Using spread attributes, we can create extremely flexible components.
  • When making a basic component (buttons, text boxes, etc) too flexible, you create a possible pitfall for you and your team.
  • While flexibility is wanted quality in some areas, basic components like buttons, text boxes, etc. should be as specific and inflexible as possible.
  • Spread attributes are great! as long as it does not make your component too flexible without a good reason

Final words

As I mentioned earlier, this is an opinionated post, based on my experience working with many agile web teams. I believe a good opinionated post can lead to good discussions and debates. Whether you like my suggestions here or not, feel free to let me know what you think in the comments section.
Cheers!

--

--