How to access slots from parent component

Hi,
My question is regarding the slots and how we can access them from the parent component dynamically using children prop?

Consumer Side Usage Plain React Props ( No Plasmic Slots involved )

<TableCell>
    <CellComponent
        tags={<TagComponent />}
        default={<LabelComponent />}
    />
</TableCell>

Library Side Code for TableCell ( only knows about a children prop )

// TableCell.tsx
// Core idea being getting the rendering component passed to either tags or default prop based on another key.

React.Children.map(cellComponent, child => {
  const childProps = child.props
  const dynamicComponent = childProps[key]       // key is either tags or default
  
  if (!dynamicComponent) return null

  return React.isValidElement(dynamicComponent) ? React.cloneElement(dynamicComponent, {...someCustomProps}) : null
}

It works perfectly fine when used as mentioned above for Customer Side Usage. I assumed that slots will be available on the children component as a normal props in the code but I found that Plasmic calculates the overrides at runtime and doesn’t expose the slots directly.

For example,
I created a component CustomCellComponent with two slots default and tags and a meta prop testProp. I assumed it will provide the children to the TableCell in Plasmic generated code as follow

<CustomCellComponent
    tags={<TagComponent />}
    default={<LabelComponent />}
    testProp={"Test value"}
/>

But it ends up being the following

<CustomCellComponent
     data-plasmic-name={"customCellComponent"}
     data-plasmic-override={overrides.customCellComponent}
     className={classNames(
         "__wab_instance",
         sty.customCellComponent
     )}
     testProp={"Test Value" as const} // testProp is a meta prop which is available here but slots aren't
/>

My question is

  1. Is it possible to expose the slots as meta props are exposed on the component in the code.
  2. If it’s not possible, how can we get the slot content considering we are in the parent component ( library code ) and the only variable we have is children which refers to the component which is exposing the slots.
  3. Another interesting caveat is that, when I console.log childProps then it logs only className and testProp where as it should log the data-plasmic-* properties as well.

@yang is there any way to manipulate to Plasmic Slots dynamically from the library code?

The only prop available is children, which refers to the Component designed in studio.

Hi @zonal_mammal! I’m not sure if I follow, which of those components are Plasmic components and where are you trying to access the slots from?

Hi @inclined_boar,
Let me explain the flow considering two components only.

  1. ComponentA ( This is a custom component which will be registered using code components )
  2. ComponentB ( This is created in Plasmic Studio ).
    a. Lets say it has a slot named SlotA and SlotB
    ComponentA can only receive ComponentB as a children.

Inside ComponentA, the only prop, I have is children I want to write some logic to get the reference to SlotA and SlotB so I can decide based on custom logic either I want to render SlotA or SlotB. or I can do anything with the Slot content as it’s a normal ReactNode.

The simplest approach would be to create two variants of ComponentB, one will render SlotA and another will render SlotB. Based on the custom logic I can activate required variant. But I want to know if it’s possible to get a reference to ComponentB’s Slots content inside ComponentA

Could you do something like…

function ComponentA({children}) {
  if (React.isValidElement(children)) {
    children.props.slotA
  }
}

I tried but it’s not possible at the moment, as I mentioned in the first message. Only meta props and className prop are available because when we sync in codegen the final output is something like this

<ComponentA>
  <ComponentB
     data-plasmic-name={"componentB"}
     data-plasmic-override={overrides.componentB}
     className={classNames(
         "__wab_instance",
         sty.customCellComponent
     )}
     testMetaProp={"Test Value" as const}
  />
</ComponentA>

~It seems like the slots are consider overrides and passed/calculated dynamically using overrides.componentB.~

image.png

hmm where does this childrenProps come from? Just tested with the following code component, it seemed to work (InnerComp is a plasmic component):

image.png

image.png

Interesting!

childrenProps is the AK Table Cell (ComponentA) children.props

I think you have used the headless loader api in the example. If that’s the case, do you think the same registration code can lead to different result while using codegen approach.

My registration approach is similar to the one followed in plasmicpkgs.

I have tried the same example you shared in codegen and it only logs className.

image.png

image.png

image.png

~I think I have figured it out. Please try adding a component inside the innerSlot instead of freebox. It will disappear from the log.~

@inclined_boar I have explained the findings in much more detail in the video. Please let me know if that helps.

Issue is that the innerSlot won’t show up when the default content isn’t changed.

oh, yea! the default contents are used when no values are provided to the slot prop, so that’s why nothing is in the props object :stuck_out_tongue:

The default contents only exist inside the inner component (so in this case, they are created inside the render function of PlasmicCustomCellComponent ). I don’t think there’s a way of retrieving them from the wrapper code component, because, when the code component renders, the React element for those contents hasn’t even been created yet

I am working on different plugins and this approach simplifies certain flows for library user.

I am curious, would it be possible to expose them by default or through some flag in Plasmic Studio in near future so I can wait for it before releasing my table component library.

One work around can be the following (but it has some caveats, not sure if it’d work for you use case):
• To create the Plasmic component ComponentB with no slots
• The wrapper component ComponentB takes React nodes as props and replaces the elements with render overrides to PlasmicComponentB (so we can use React refs to the element):
• We register the wrapper component (ComponentB) as a code component so those props can be used as normal slots in the Studio
One caveat is if we tweak the design of ComponentB in the studio, it’ll need to sync the code for the changes to be applied to the instances

Yeah!!!, but as a developer of library, I can only write some logic for ComponentA
I don’t have access to ComponentB. That way I will have to enforce the mentioned logic by conveying it to the library users.

If the default slots were exposed by the Plasmic as discussed in the video shared above, I could simply assume a generic structure after plasmic sync and could write a generic logic on top of it so that library users don’t have to write extra code.