Skip to main content

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

PropTypeDefaultDescription
childrenReactNode-Exactly one element, such as an <a> or a Next.js Link, to render instead.
refRef<HTMLElement>-Gets the child's element, along with the child's own ref.
Any HTML attributeHTMLAttributes<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 with cn(), the child's classes last, so they win a conflict
  • style: 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 called preventDefault()
  • 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 and ref on 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.

© Anantya TechLabs. All rights reserved.