Polymorphic Slot
A flexible component that allows dynamic rendering of its children as different HTML elements or components, while preserving props and context.
A flexible component that allows dynamic rendering of its children as different HTML elements or components, while preserving props and context.
Basic usage example to quickly see how the PolymorphicSlot works.
Combines and passing data with a render props onto its immediate child.
asChild prop will pass all the props you created yourself even the Slot ref to its direct child.ref, attributes and event handlers according to the el="" you use,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:
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>
);
}Full working code example, including necessary markup and styles. You can copy and paste this code directly to start using the component immediately.