puck icon indicating copy to clipboard operation
puck copied to clipboard

Include additional props when using the `as` prop in Slots

Open FedericoBonel opened this issue 4 weeks ago • 1 comments

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.

FedericoBonel avatar Nov 26 '25 10:11 FedericoBonel

Maybe a solution similar to radix slot would be better:

render: ({ SlotComponent, height }) => {
  return <SlotComponent asChild>
    <Box sx={{ height: (theme) => theme.units * height }} />
  </SlotComponent>
}

cihad avatar Dec 01 '25 23:12 cihad

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?

FedericoBonel avatar Dec 04 '25 06:12 FedericoBonel

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.

cihad avatar Dec 04 '25 12:12 cihad