Build a Polymorphic Component in React and TypeScript

Boluwatife Fakorede
JavaScript in Plain English
2 min readDec 1, 2021

--

Photo by Kelly Sikkema on Unsplash

“A polymorphic component is a component that can act in more than one way depending on how it is instantiated”.

I am currently working on a component library, and one of the features I want to support is the user of this library to be able to change the type of Component initially set by me.

Let’s build a Title component for a modal dialog that is to be accessible.

The code above signifies a simple Title component, but what if the consumer of the Modal wants the Title to be a link or some other HTML element? How can we support more than one type of HTML element?. We could easily do this.

N.B: The Component must be capitalized else jsx will treat it as an HTML tag <component>.

The name of the type has changed to “TitleOwnProps,” which represents props that we have defined ourselves, and it receives an “as” prop, which is of type “React.ElementType” (it should be an HTML element). Also, I am spreading the rest of the props, but that won’t help much as the “href” we are passing into the Title is not recognized as a valid prop, and also, the type of Component is still of type “any.” We can resolve the above issue in different ways, but I will demonstrate using generics.

The “TitleOwnProps” is now expecting a generic type, and the “as” prop is set to the type passed. The generic type extends the “React.ElementType”; hence, it will not be of type “any” but an HTML element.

We also need to create a “TitleProps,” which will pick all of the generic types props and override them with our unique types passed if they exist in our types.

With Omit, I carefully picked all of the React.ComponentProps for the type passed and removed our TitleOwnProps keys since we will pass it in ourselves and merge everything into one prop Type “TitleProps.” Now our Title component can receive this new prop.

Now we can have a generic component as shown below:

The Title component receives a generic; type of “h2” tag by default. That means that our TitleProps by default is an h2, but typescript can infer generic functions types. This enables us to pass an HTML element to “as” and gives us a dynamic component that functions correctly.

More content at plainenglish.io. Sign up for our free weekly newsletter here.

--

--

A frontend developer, while at that, just a curious cat that loves to share what he knows.