Include additional props when using the `as` prop in Slots
Description
Currently, using the as slot render prop to provide your own components or elements for slots does not support passing down additional props. While that might be fine for some cases, there are many situations where we want to pass props to the component we use for the slot.
Proposal
Similar to how MUI handles it, we could allow any additional props to be passed to the component provided:
render: ({ SlotComponent, height }) => {
// Example: Box accepts an sx prop for styling with your own theming solution
return <SlotComponent as={Box} sx={{ height: (theme) => theme.units * height }} />
}
For implementation, the slot render function could capture all remaining props via spreading, and then apply them to the component when it renders.
Maybe a solution similar to radix slot would be better:
render: ({ SlotComponent, height }) => {
return <SlotComponent asChild>
<Box sx={{ height: (theme) => theme.units * height }} />
</SlotComponent>
}
Hey @cihad! Thanks for the suggestion.
We already have the as prop implemented and merged, so we probably won't change the API for now. If we implement prop spreading, it should behave pretty similarly to the Radix slot version (Slots in Puck mean something different than in Radix.)
I think adding asChild to a slot in Puck (which is essentially a dropzone) might be confusing from a readability point of view, since it could imply that the child is going to be dropped inside the slot by default.
That said, is there a specific reason you prefer that approach?
Previously I was wrapping the slot with another element, specifically for puck.dragRef, like this:
<Card>
<div ref={puck.dragRef}>
<Children className="grid gap-3" />
</div>
</Card>
I noticed that I can now ref the slot component:
<Card>
<Children ref={puck.dragRef} className="grid gap-3" />
</Card>
This way, the method I suggested above is no longer necessary for now. It might be needed at very extreme use cases, such as when you want to assign an event to a component. Of course, these would be extreme use cases. But asChild would definitely offer a more flexible structure. Or, consider something like this:
<SlotComponent>
{({ children, isEmpty }) => {
return ...
})
</SlotComponent>
This way a component-specific placeholder can be provided.