Foundations
Slot
BetaSince 0.1.0
Renders its one child in place of its own element, so a component can take asChild.
import { Slot } from "@anantya/uix";Overview
Slot renders its one child element in place of an element of its own, with its props merged onto that child. UIX components use it for their asChild prop. In product code, use it only for a wrapper that adds behavior without adding markup, such as counting clicks.
Building block
To render a UIX component as a link, pass it asChild, such as <Button asChild>.
Missing a component? Ask for it instead of building your own.
Signature
function Slot(props: SlotProps): ReactElement | null;
interface SlotProps extends HTMLAttributes<HTMLElement> {
children?: ReactNode;
ref?: Ref<HTMLElement>;
}Parameters
| Prop | Type | Default | Description |
|---|---|---|---|
children | ReactNode | - | Exactly one element, such as an <a> or a Next.js Link, to render instead. |
ref | Ref<HTMLElement> | - | Gets the child's element, along with the child's own ref. |
| Any HTML attribute | HTMLAttributes<HTMLElement> | - | Merged onto the child, such as className, style or onClick. |
Returns
The child element, with Slot's props merged onto it:
className: both are joined withcn(), the child's classes last, so they win a conflictstyle: both objects are merged, and the child's values win- Event handlers, such as
onClick: the child's runs first, then Slot's, unless the child's calledpreventDefault() ref: both refs get the element- Every other prop: the child's value wins, unless it is
undefined
Example
TrackClicks adds an onClick to whatever it wraps, here a Button, without adding an element.
The Button's own onClick would run first.
Downloaded 0 times
Code
"use client";
import { Download } from "@anantya/icons";
import { Button, Slot } from "@anantya/uix";
import { type ReactElement, useState } from "react";
function TrackClicks({ onTrack, children }: { onTrack: () => void; children: ReactElement }) {
return <Slot onClick={onTrack}>{children}</Slot>;
}
export default function TrackDownloads() {
const [downloads, setDownloads] = useState(0);
return (
<div className="flex flex-col items-center gap-2 text-sm">
<TrackClicks onTrack={() => setDownloads((count) => count + 1)}>
<Button variant="secondary" icon={<Download />}>
Download PDF
</Button>
</TrackClicks>
<p className="text-muted-foreground">Downloaded {downloads} times</p>
</div>
);
}Notes
- Slot needs exactly one element as its child. Text, a Fragment, several children or nothing throws an error in development that says what it got, and renders nothing in production
- When the child is a component of your own, it must pass
className,style, its event handlers andrefon to its element, or they are lost - Slot renders on the server too, so a component that uses it can be a server component
Changelog
Every change to Slot since 0.1.0 is in the release notes.