Slot
The Slot
component merges its props onto its immediate child,
enabling flexible prop forwarding and event handling across your components.
This utility is inspired by @radix-ui/react-slot.
Setup
Define and export the Slot
component.
import { defineSlot } from 'crustack/slot'
export const Slot = defineSlot()
Use the strict
option to prevent the Slot props from being overriden by the child’s props. See the detailed behavior section for more info.
import { defineSlot } from 'crustack/slot'
export const StrictSlot = defineSlot({ strict: true })
Examples
1. Enhancing Child Functionality
With the Slot
component, you can easily enhance the functionality
of a child element by forwarding props such as event handlers.
import { Slot } from './slot'import { ReactNode } from 'react'
function Trigger(props: { children: ReactNode }) { return ( <Slot onClick={() => console.log('Do something to open a modal')}> {props.children} </Slot> )}
Usage:
import { Trigger } from './your-trigger'
export default () => ( <Trigger> <Button>Open</Button> </Trigger>)
Here, clicking the button within the Trigger
will log a message to the console
and could trigger further functionality, such as opening a modal.
2. Add asChild
prop
The Slot
component can be used with an asChild
prop to replace the underlying HTML element,
making the component highly reusable while maintaining prop merging behavior.
import { Slot } from './slot'import { ReactNode } from 'react'
type Props = ComponentProps<'button'> & { asChild?: boolean}
function Button(props: Props) { const Comp = asChild ? Slot : 'button' return <Comp {...props} />}
Usage:
import { Button } from './your-button'
export default () => ( <Button asChild> <a href="/contact">Contact</a> </Button>)
In this example, the Button component wraps an anchor tag, allowing the link to inherit button-like behavior while preserving the original anchor styles and attributes.
Detailed behavior
- Event Handlers: props beginning with
on
are merged. Child handlers are invoked before the slot handlers. - Styles: The
style
prop is merged. Child styles take precedence and override any conflicting styles from theSlot
. - ClassNames: The
className
prop is also merged. - Other props:
- when
strict: false
the child’s props override those of the slot. - when
strict: true
an Error is thrown if both the Slot and the child define the same prop.
- when