Alfonso's Website
3 min read time

Efficient Prop Declarations in React Components

When working with React components, it's important to define the props a component can accept. However, defining every single prop for a component can become tedious and result in a lot of boilerplate code.

One way to reduce the amount of code needed to define props is to inherit props from the HTML element inside the component. For example, instead of defining all the props for a <button> element, you can inherit the props from the HTML element and only define the "custom" ones.

Let's take a look at an example component:

interface Props {
  onClick: () => void;
  customProp: boolean;
}

function SomeButton({ customProp = false, onClick }: Props): JSX.Element {
  if (customProp) {
    // do something
  }

  return <button onClick={onClick} />;
}

In this example, the SomeButton component has two props: onClick and customProp. If we want to add a className prop to the button, we can't do so because we did not define it in the Props interface.

// this is not valid because we don't have a `className` prop
<SomeButton customProp onClick={doSomething} className="p-3" />

To solve this problem, we can define the props by extending React.ButtonHTMLAttributes<HTMLButtonElement>. This means that we can add any prop that a regular button accepts.

interface Props extends React.ButtonHTMLAttributes<HTMLButtonElement> {
  customProp?: boolean;
}

function SomeButton({ customProp = false, ...props }: Props): JSX.Element {
  if (customProp) {
    // do something
  }

  return <button {...props} />;
}

With this updated implementation of SomeButton, we can now add the className prop, along with any other prop that a regular button accepts.

// this works
<SomeButton customProp onClick={doSomething} className="p-3" {...anyOtherProp} />

This technique can be applied to any HTML element that a component is based on. For example, if the component is based on a <div> element, we can inherit props from React.HTMLAttributes<HTMLDivElement> instead.

interface Props extends React.HTMLAttributes<HTMLDivElement> {
  customProp?: boolean;
}

By inheriting props from the HTML element inside a component, we can reduce the amount of boilerplate code needed to define props, while still allowing us to add any prop that the HTML element accepts.