This content originally appeared on DEV Community and was authored by Fabio Biondi
In the front-end ecosystem, UiKits are collections of utilities and several components, such as:
<Card />
<TabBar />
<Carousel />
-
<Row />
and<Col />
<GoogleMap />
Each component has usually its own custom layout and could accepts several properties. For example, a "Google Map" component could accept the "coordinates" and a "zoom" value as properties:
<GoogleMap coords={coords} zoom={zoom} />
Sometimes we need to create components whose layout is created from scratch. In other cases their layout may be based of native elements.
Some examples:
-
<MyButton />
: that extends<button>
element capabilities -
<MyImg />
: that extends<img>
element - and so on.
Let's imagine a button
component that must display an icon next to the label that I can use as shown below:
<MyButton icon="💩"> CLICK ME </MyButton>
This component should accept the icon
and children
properties and its definition may looks like the following:
interface MyButtonProps {
icon: string;
}
function MyButton(props: PropsWithChildren<MyButtonProps>) {
const { icon, children } = props;
return <button className="btn btn-primary">
{icon} {children}
</button>
}
So we can use the component in this way:
<MyButton icon="💩"> DO SOMETHING</icon>
<MyButton icon="😱"> CLICK ME</icon>
OUTPUT
THE PROBLEM
In order to work fine, our MyButton
component should also accepts all the native button
properties. For example we may need to listen the onClick
event or disabled it:
<MyButton icon="💩" onClick={...} disabled={...} />
So we should add them to the Component's Property Type and apply them as attributes of the <button>
element:
// 1. Add the properties
interface MyButtonProps {
icon: string;
disabled: boolean; // ➡️ native prop
onClick: (e: React.MouseEvent) => void; // ➡️ native prop
// ➡️ other native props
}
function MyButton(props: PropsWithChildren<MyButtonProps) {
const { icon, children, onClick, disabled } = props;
// 2. apply all props one by one
return <button disabled={disabled} onClick={onClick} className="btn btn-primary">
{icon}
{children}
</button>
}
Should I add all the HTMLButtonElement
properties to the component type and apply them one by one? Nahh : )
That's too much work and I'm sure I'll forget some properties 😓
SOLUTION
What we can do to avoid all this work?
We can simply use an intersection type to combine our custom props with all the HTMLButtonElement
properties to automatically support all native buttons properties:
export function MyButton(
props: PropsWithChildren<MyButtonProps & React.ButtonHTMLAttributes<HTMLButtonElement>>
) {
// ... component here ...
}
Now your component supports all buttons properties and we can apply them simply using this trick:
// apply all props as button attributes
return <button className="btn btn-primary" {...props}>
However icon
and children
are not valid button's properties so we'll use the following "trick" (destructuring) to create a rest
property that contain all the properties except icon
and children
:
const { icon, children, ...rest } = props;
// Now we apply all props except icons and children
return <button className="btn btn-primary" {...rest}>
{icon}
{children}
</button>
And that's all.
Here our final source code to create a button that support icon
, children
and all native button properties:
import { PropsWithChildren } from 'react';
interface MyButtonProps {
icon: string;
}
export function MyButton(
props: PropsWithChildren<MyButtonProps & React.ButtonHTMLAttributes<HTMLButtonElement>>
) {
const { icon, children, ...rest } = props;
return <button className="btn btn-primary" {...rest}>
{icon}
{children}
</button>
}
USAGE EXAMPLE:
<MyButton
icon="💩"
type="submit"
disabled={...}
onClick={...}
onMouseOver={...}
> CLICK ME </MyButton>
This content originally appeared on DEV Community and was authored by Fabio Biondi

Fabio Biondi | Sciencx (2022-07-08T21:50:24+00:00) How to create React UIKIT components in TypeScript that extends native HTML Elements. Retrieved from https://www.scien.cx/2022/07/08/how-to-create-react-uikit-components-in-typescript-that-extends-native-html-elements/
Please log in to upload a file.
There are no updates yet.
Click the Upload button above to add an update.