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
asChildprop will pass all the props you created yourself even the Slotrefto its direct child. - Using
ref,attributesandevent handlersaccording 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.