Extending the Properties of HTML elements in React and TypeScript
Add to your RSS feed29 November 20232 min readTable of Contents
When working with React and TypeScript, you might want to extend the properties of HTML elements to include additional attributes or custom properties. This can be achieved by defining a TypeScript interface that extends the base HTML element type.
Here's an example demonstrating how to extend the properties of an Button element:
1 type ButtonType = 'black' | 'white';23 interface ButtonProps4 extends DetailedHTMLProps<ButtonHTMLAttributes<HTMLButtonElement>, HTMLButtonElement> {5 children: ReactNode;6 appearance: ButtonType;7 disabled: boolean;8 }910 const Button = ({11 children,12 appearance,13 disabled = false,14 className,15 ...props16 }: ButtonProps): JSX.Element => {17 return (18 <button19 className={`group px-6 py-3 font-primary font-semibold text-base rounded-xl flex gap-2 max-w-fit20 max-h-[52px] self-end disabled:bg-gray-50 ${21 appearance === 'black' &&22 'bg-gray-800 text-white hover:bg-gray-700 hover:text-gray-100 hover:gap-3'23 } ${appearance === 'white' && 'bg-gray-200 text-gray-700 hover:bg-gray-100'} ${className}`}24 disabled={disabled}25 {...props}26 >27 {children}28 </button>29 );30 };31 export default Button;
In this example:
ButtonProps is an interface that extends React.DetailedHTMLProps<ButtonHTMLAttributes<HTMLButtonElement>, HTMLButtonElement>. This means it includes all the standard HTML button element properties. The appearance, children, and disabled properties is added to ButtonProps, providing a way to extend the properties with custom attributes.
The Button component is a functional component that takes ButtonProps as its prop types. Inside the component, the custom properties is destructured, and the rest of the input properties are spread onto the button element. This pattern allows you to extend the properties of HTML elements with custom attributes while leveraging TypeScript for type safety. You can apply a similar approach to other HTML elements by creating interfaces that extend their respective React types, such as React.DetailedHTMLProps<DivHTMLAttributes<HTMLDivElement>, HTMLDivElement>, DetailedHTMLProps<TextareaHTMLAttributes<HTMLTextareaElement>, HTMLTextareaElement>, etc.
Example usage of the Button component
1 <Button2 appearance='black'3 className='w-full'4 disabled={disabled}5 onClick={(e: MouseEvent<HTMLButtonElement, MouseEvent>) => doSomething(e)}6 >7 Do Something!8 </Button>
Conclusion:
By defining additional props and spreading them onto the underlying HTML elements, you can extend their behavior while leveraging TypeScript's type system for increased safety and productivity.