Polymorphic Slot
A flexible component that allows dynamic rendering of its children as different HTML elements or components, while preserving props and context.
Usage
Basic usage example to quickly see how the PolymorphicSlot
works.
API References
Combines and passing data with a render props onto its immediate child.
Support
- The
asChild
prop will pass all the props you created yourself even the Slotref
to its direct child. - Using
ref
,attributes
andevent handlers
according to theel=""
you use, - Freestyle variables are used without affecting the default style
Alternative
By default we use twMerge
to prioritize the tailwindcss style of PolymorphicSlot
over its immediate child style. You can customize it at any time if you are not using tailwindcss.
If you prefer to use Slot
from radix you can combine Polymorphic
with radix dependencies using the following command:
- Install @radix-ui/react-slot
- Import dependencies and Customize PolymorphicSlot:
import * as React from "react";
import { Slot as PolymorphicSlot } from "@radix-ui/react-slot";
const Slot = <T extends React.ElementType = "div">({ asChild = false, el, ...props }: ElementType<T>, ref: PolymorphicSlotRef<T>) => {
const Component = asChild ? PolymorphicSlot : ((el || "div") as React.ElementType);
return <Component ref={ref} {...props} />;
};
If you don't need the element to pass its props, you can simplify it in a nutshell as below:
import * as React from "react";
export type PolymorphicRef<T extends React.ElementType> = React.ComponentPropsWithRef<T>["ref"];
export type PolymorphicWithoutRef<T extends React.ElementType, Exclude extends string = never> = Omit<React.ComponentProps<T>, "ref" | "style" | Exclude> & {
el?: T;
style?: React.CSSProperties & {
[key: string]: any;
};
};
const Element = <T extends React.ElementType = "div">({ el, ...props }: PolymorphicWithoutRef<T>, ref: PolymorphicRef<T>) => {
const Component = (el || "div") as React.ElementType;
return <Component ref={ref} {...props} />;
};
export default React.forwardRef(Element) as <T extends React.ElementType = "div">(props: PolymorphicWithoutRef<T> & { ref?: PolymorphicRef<T> }) => React.ReactElement | null;
ref and all property default as div
function MyComponent() {
return <Polymorphic />;
}
function MyComponent() {
return <Polymorphic el="a" href="" />;
}
function MyComponent() {
return <Polymorphic el="img" src="" />;
}
function MyComponent() {
return (
<Polymorphic
el="nav"
style={{
width: "var(--sz)",
height: "var(--sz)",
"--sz": "0.75rem",
"--bg-open": "var(--background)"
}}
/>
);
}
Passing ref
and attributes
to element or component as a single child
function MyComponent() {
const containerRef = useRef < HTMLElement > null; // if usage with ref
return (
<Polymorphic
ref={containerRef}
asChild
style={{
width: "var(--sz)",
height: "var(--sz)",
"--sz": "0.75rem",
"--bg-open": "var(--background)"
}}
>
<aside>
<h6>Title</h6>
<section>Content</section>
<section>Content</section>
</aside>
</Polymorphic>
);
}
Source Codes
Full working code example, including necessary markup and styles. You can copy and paste this code directly to start using the component immediately.