Sometimes we need to overload some native HTML tags with our own component.
Let’s take a simple example.
You need to create a Button
component but you want your button
to have a custom style. You’ll probably write something like :
interface ButtonProps {
value: string;
}
const Button = (props: ButtonProps) => {
return (
<button className="myClass">{value}</button>
)
}
This code is totally fine. However, what happens if you want to pass some native attributes to your button
like the onClick
method or the type
? You’ll surely add props to your interface
:
interface ButtonProps {
value: string;
type: string;
onClick: (e: React.MouseEvent<HTMLButtonElement, MouseEvent>) => void;
}
const Button = (props: ButtonProps) => {
const {value, onClick, type} = props;
return (
<button
onClick={onClick}
type={type}
className="primary">
{value}
</button>
);
}
Well, our code is still ok. Now, we also want to pass our classes dynamically to our component:
interface ButtonProps {
value: string;
type: string;
onClick: (e: React.MouseEvent<HTMLButtonElement, MouseEvent>) => void;
className: string;
}
const Button = (props: ButtonProps) => {
const {value, onClick, type, className} = props;
return (
<button
onClick={onClick}
type={type}
className={className}>
{value}
</button>
);
}
const App = () => {
return (
<div>
<Button
type="button"
value="Submit"
onClick={(e) => {console.log("Clicked!"}}
className="primary"
/>
</div>
);
}
Do you see the problem with this approach? Each time we’ll need to use a native property of our button
tag, we will need to add a property to our interface to be able to overload it in our component.
Fortunately, we can change our interface to avoid these repetitions :
interface ButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {}
export default function Button(props: ButtonProps) {
return <button {...props}>{props.value}</button>;
}
In this way, you can pass all the previous props
to your component without adding every attribute in your interface
because it extends all the button tag native attributes :
<Button
value='Submit'
type='button'
onClick={(e) => {
console.log("submitted!");
}}
className='primary'
/>
Furthermore, a big advantage of this approach is that you can overload the attribute in your component in order to have more control :
interface ButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {}
export default function RadiusButton(props: ButtonProps) {
// Here we overload the className and add our own class to the button
return (
<button {...props} className={`${props.className border-radius}`} >
{props.value}
</button>
);
}
So next time you need to create a basic component with custom attributes, try to extend your component with native HTML Element attributes.
Top comments (0)