Great Q @niall!
We have a section in our docs that should help you out with this here Using Your React Components in Builder.io - Builder.io
Easy mode
For most cases of needing children, you just need to use our withChildren
function, e.g.
import { Builder, withChildren } from '@builder.io/react';
export const Hero = props =>
<div className={heroStyles}>{div}</div>
const HeroWithBuilderChildren = withChildren(Hero)
Builder.registerComponent(HeroWithBuilderChildren, {
name: 'Hero',
// Adding defaults is important for easy usability
defaultChildren: [
{
'@type': '@builder.io/sdk:Element',
component: { name: 'Text', options: { text: 'I am child text block!' } }
}
]
})
You can see some helpful examples in our design system example project, specifically with this component
Advanced mode
For your use case with tabs though, where you will likely want different children per tab, you will want a slightly more advanced option.
Instead of using withChildren
for a tabs example, we’ll specify we’ll take child elements as an input to our component (type: 'uiBlocks'
) and render out multiple sets of children (e.g. in this case one per tab).
You can also see the source code of all of our built-in components in our Github repo, e.g. the full source of the tabs component is here.
You’ll see that it dynamically renders multiple sets of children, depending on which tab is selected.
You’ll also find that instead of using {props.children}
it uses the <BuilderBlocks />
component. This adds one more nuanced behavior which is any time there are no children, it shows a big “+ new block” button in the editor to point the users attention to add a block inside (vs displaying nothing inside and possibly creating confusion how to add tab content)
E.g. see here
{this.activeTabSpec && (
<BuilderBlocks
parentElementId={this.props.builderBlock.id}
dataPath={`component.options.tabs.${this.state.activeTab}.content`}
blocks={this.activeTabSpec.content}
/>
)}
This tabs component input schema uses a list
so you can have a + new tab
option, and then for each tab renders it’s label
and content
. You can see the schema here, namely:
export const Tabs = withBuilder(TabsComponent, {
name: 'Builder: Tabs',
inputs: [
{
name: 'tabs',
type: 'list',
subFields: [
{
name: 'label',
type: 'uiBlocks',
hideFromUI: true,
defaultValue: [defaultTab]
},
{
name: 'content',
type: 'uiBlocks',
hideFromUI: true,
defaultValue: [defaultElement]
}
],
...
Block JSON format
You can then add default children using our JSON format that you can see here, simplest example would be something like
{
'@type': '@builder.io/sdk:Element',
component: {
name: 'Text',
options: {
text: 'New tab'
}
}
}
To have a new text block inside each tab.
To get a sense of the JSON format for default values, you can select any block in the UI, and go to the “data” tab on the left and choose “toggle json view” at the very bottom left to see the JSON for every element, and you can copy + modify them for child element defaults
Hope this helps and let us know if you have any followup Qs or we can explain anything better!