npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2025 – Pkg Stats / Ryan Hefner

react-polymorphic-forwardref

v0.0.9

Published

Provides an enhanced version of "React.forwardRef" to polymorph using the "as" prop.

Readme

react-polymorphic-forwardref

This package is heavily inspired by react-polymorphed and addresses changes introduced in TypeScript version 5.x.x.

In addition to supporting polymorphism with native HTML elements, it also enables polymorphing into existing polymorphic components.

Basic Usage

import { forwardRefAs } from 'react-polymorphic-forwardref'

interface MyPolymorphicComponentProps {
    text: string
}

const MyPolymorphicComponent = forwardRefAs<'div', MyPolymorphicComponentProps>((props, ref) => {
    const {as, text} = props;

    const Component = as || 'div';

    return <Component ref={ref}>{text}</Component>;
});

export const App = () => {
    return (
        <MyPolymorphicComponent
            as='button'
            text='Click me'
            onClick={(e) => alert('The type of "e" is automatically recognized as "React.MouseEvent<HTMLButtonElement, MouseEvent>"')}
        />
    );
}

App();

Automatically receive native HTML prop typings

On the above example, MyPolymorphicComponent uses div element by default for render, inheriting all native HTML attributes for a div.

Let's consider onClick method and its typing. onClick method provides an e parameter, which is typed based on the HTML element it is assigned to. If the polymorped component is a div element, then Typescript recognizes the default type of e as React.MouseEvent<HTMLDivElement, MouseEvent>.

<MyPolymorphicComponent
    text='I am a "div" element'
    // "e" receives its typing automatically as "React.MouseEvent<HTMLDivElement, MouseEvent>"
    onClick={(e) => alert('"e" typing is "React.MouseEvent<HTMLDivElement, MouseEvent>"')}
/>

<MyPolymorphicComponent
    text='I am a "div" element'
    // ERROR: HTMLAnchorElement is not valid, since by default, it needs to be HTMLDivElement
    onClick={(e: React.MouseEvent<HTMLAnchorElement, MouseEvent>) => alert('Cannot define "e" as HTMLAnchorElement, I am a "div" element!')}
/>

Since this is a polymorphic component, its HTML element render can be modified based on where the component is consumed.

Let's say that we would like to polymorph this component into an Anchor (a) tag. We can accomplish this by simply providing the as prop to the component. Once we provide as="a", we expect 2 things to happen:

  • The e parameter of onClick should now be redefined based on the HTMLAnchorElement, effectively typing it as React.MouseEvent<HTMLAnchorElement, MouseEvent>.
  • Native HTMLAnchorElement properties should be immediately available, such as href and target.
<MyPolymorphicComponent
    as='a'
    text='I am an "a" element now'
    // Typescript will recognize the typings for "href" and "target"
    href="#"
    target="_blank"
    onClick={(e) => alert('Yeap, you guessed it right, "e" typing is "React.MouseEvent<HTMLAnchorElement, MouseEvent>"')}
/>

Polymorphing into Another Polymorphic Component

What if we were polymorphing into another polymorphic component? In this case, the polymorphed component should inherit all the props of the polymorphed component, including the native properties of the default HTML element and the explicitly defined props.

Let's build another polymorphic component, to be later polymorphed into MyPolymorphicComponent

import { forwardRefAs } from 'react-polymorphic-forwardref'

interface AnotherPolymorphicComponentProps {
    anotherText: string
}

const AnotherPolymorphicComponent = forwardRefAs<'a', AnotherPolymorphicComponentProps>((props, ref) => {
    const {anotherText} = props

    return <div>{anotherText}</div>
})

If this component is rendered without polymorphing, it would automatically receive the Anchor element related native HTML props, as well as anotherText prop, which is required.

<AnotherPolymorphicComponent
    // "anotherText" is an explicity defined prop
    anotherText='I am a prop of "AnotherPolymorphicComponent'
    // "e" typing will inherit the default HTML element of "AnotherPolymorphicComponent", which is an "a" tag.
    // Hence, its type will be "React.MouseEvent<HTMLAnchorElement, MouseEvent>"
    onClick={(e) => alert('"e" type is React.MouseEvent<HTMLAnchorElement, MouseEvent>')}
/>

Now let's polymorph AnotherPolymorphicComponent into MyPolymorphicComponent.

  • AnotherPolymorphicComponent is going to inherit all the properties of MyPolymorphicComponent, including the text prop and the native HTML attributes for the default HTML element of MyPolymorphicComponent.
  • anotherText prop that is required for AnotherPolymorphicComponent will be added on top of the inherited props.
<AnotherPolymorphicComponent
    as={MyPolymorphicComponent}
    // "text" prop is enherited, since it is a required prop of `MyPolymorphicComponent`
    text='I am a prop that is automatically inherited'
    anotherText='I am a prop of "AnotherPolymorphicComponent'
    // "e" typing will inherit the default HTML element of "MyPolymorphicComponent", which is a "div" tag.
    // Hence, its type will be "React.MouseEvent<HTMLDivElement, MouseEvent>"
    onClick={(e) => alert('"e" type is React.MouseEvent<HTMLDivElement, MouseEvent>')}
/>