Skip to content

Instantly share code, notes, and snippets.

@typeofweb
Created February 12, 2024 10:22
Show Gist options
  • Save typeofweb/06b01e6248c57d0d35c20462cc06eb91 to your computer and use it in GitHub Desktop.
Save typeofweb/06b01e6248c57d0d35c20462cc06eb91 to your computer and use it in GitHub Desktop.
`asChild` pattern in React
import { clsx } from "clsx";
import { type ButtonHTMLAttributes } from "react";
import { Slot } from "./Slot";
interface ButtonProps extends ButtonHTMLAttributes<HTMLButtonElement> {
asChild?: boolean;
children: React.ReactNode;
}
export const Button = ({ asChild = false, ...props }: ButtonProps) => {
const Comp = asChild ? Slot : "button";
return (
<Comp
{...props}
className={clsx(
"………",
props.className,
)}
/>
);
};
// https://www.jacobparis.com/content/react-as-child
import clsx from "clsx";
import { isValidElement, cloneElement, Children } from "react";
export const Slot = ({
children,
...props
}: React.HTMLAttributes<HTMLElement> & {
children?: React.ReactNode;
}) => {
if (isValidElement(children)) {
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument
return cloneElement(children, {
...props,
...children.props,
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument, @typescript-eslint/no-unsafe-member-access
className: clsx(children.props.className, props.className),
});
}
if (Children.count(children) > 1) {
Children.only(null);
}
return null;
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment