DEV Community

Cover image for Polymorphic component
M. Akbar Nugroho
M. Akbar Nugroho

Posted on

Polymorphic component

TL;DR

Polymorphic component is a React component that has ability to use other HTML element as the returned element.



// Example of polymorphic component
<Button as="a" href="...">
  About
</Button>


Enter fullscreen mode Exit fullscreen mode

With this approach, it gives you a control to customize the returned element from a component.

This is one of UI component that implement polymorphic component.

GitHub logo mantinedev / mantine

A fully featured React components library

Mantine

NPM GitHub contributors npm npm Help wanted Discord X Follow

Links

Packages

Getting help

Mantine has a very friendly community, we are always happy to help you get started:

Introduction

When building user interface, we often facing an issue where a component not flexible enough.

Let's say you have a component like this.



function Button({ children, ...props }) {
  return <button {...props}>{children}</button>;
}


Enter fullscreen mode Exit fullscreen mode

You can use component above to create a beautiful button. Nothing wrong with that component. Until someday you want create a link with same style with the <button /> component.

Maybe you will use this approach.



<a href="...">
  <Button>To next page</Button>
</a>


Enter fullscreen mode Exit fullscreen mode

Of course it should work, but the code doesn't look so fluent. Meaning to say. If you use HTML, you can write it like this:



// We assume <a /> using same styling with <button />
<a href="...">To next page</a>


Enter fullscreen mode Exit fullscreen mode

Based on the problem above, polymorphic component offers you a solution like this:



<Button as="a" href="...">To next page</a>


Enter fullscreen mode Exit fullscreen mode

See? You don't need to wrap the <Button /> component using <a /> because it's automatically convert the the returned element to <a />.

Building The Component

Now let's build the component and it's very easy. All you need is only React createElement API.

💡NOTE:
Read the createElement API documentation for more information.


We have this component from the previous section.



function Button({ children, ...props }) {
  return <button {...props}>{children}</button>;
}


Enter fullscreen mode Exit fullscreen mode

From this normal component, we will refactor it to polymorphic component.



function Button({ children, as, ...props }) {
  return React.createElement(as || 'button', props, children);
}


Enter fullscreen mode Exit fullscreen mode

Let me explain the code above.



- function Button({ children, ...props }) {
+ function Button({ children, as, ...props }) {
  return React.createElement(as || 'button', props, children);
}


Enter fullscreen mode Exit fullscreen mode

Here we added as props. This props holds a value of what element will returned.

It's not a must to name it as. Some UI library name it element, component, or whatever you like.



function Button({ children, as, ...props }) {
- return <button {...props}>{children}</button>;
+ return React.createElement(as || 'button', props, children);
}


Enter fullscreen mode Exit fullscreen mode

We also changed the JSX to createElement API to give us more control when creating the component.

If you not familiar. Actually when you use JSX, under the hood it will transform your code to createElement.

By using the createElement API, we are able to conditionally create a component. That's why when you are not passing a value into the as props, the default element of <Button /> component is <buttton />.

And that's it... You have created a polymorphic component.

Conclusion

Polymorphic component may sounds very fancy and difficult, but it's not.

The term of polymorphic is a general term in computer science. You can read about it here.

One of my favorite backend framework, Laravel, is also has a feature called polymorphic relationships which use this term.

In React world, polymorphic component refers to an ability of a component that can returns different element with a same style without removing the default functionality.

It's really help when you facing a problem where you want to use other HTML with a same style.

I hope it gives you something. Thanks for reading :)

Buy Me A Coffee

Top comments (0)