React children as array/object
What do you do when you want to pass in children as an array or as an object, or as a const. I'll give an example below.
Breadcrumbs example
For Breadcrumbs, the number of "crumbs" ends up being an array of children, so we've hooked up our main breadcrumb component and 2 subcomponents. Here's a screenshot of our Figma component:
Link Crumb Subcomponent
Below is a screenshot of the subcomponent and then the connect statement. Same code for every variant because the browser handles the hover and active states.
figma.connect(
Link,
"https://www.figma.com/design/<OBFUSCATED>",
{
props: { text: figma.textContent("✏️ Text") },
example: ({ text }) => (
<Link inline={true} size="small">
<a href={'INSERT_URI'}>{text}</a>
</Link>
),
},
);
Current Crumb Subcomponent
Below is a screenshot of the subcomponent and then the connect statement.
figma.connect(
Link, // just a dummy placeholder, no real component
"https://www.figma.com/design/<OBFUSCATED>",
{
props: { text: figma.textContent("✏️ Text") },
example: ({ text }) => (
<>
<span aria-hidden="true">{text}</span>
<span className="is-visually-hidden">Current page {text}</span>
</>
),
},
);
Breadcrumbs Component with children
To tie it all together, below is the code connect statement for the Breadcrumbs component:
figma.connect(
Breadcrumbs,
"https://www.figma.com/design/<OBFUSCATED>",
{
props: {
items: figma.children(["_ ⚙️ Link crumb", "_ ✏️ Current crumb"]),
hasDynamicInlineCrumbs: figma.boolean("Menu Toggle"),
},
example: ({ hasDynamicInlineCrumbs, items }) => {
const [showMenu, setShowMenu] = React.useState(false);
const handleTrigger = (e) => {
setShowMenu(!showMenu);
};
const crumbs = { items };
return (
<EGDSBreadcrumbs isOpen={showMenu} onTriggerClick={handleTrigger} hasDynamicInlineCrumbs={hasDynamicInlineCrumbs} crumbs={crumbs} />
);
},
},
);
Now, this renders them all in the right order, but the crumbs const should be an array of children, but instead it is a concatenation of the children. Is there any way to manipulate that?
Expected rendering
const crumbs = [
<Link inline={true} size="small"><a href={'INSERT_URI'}>Link crumb</a></Link>,
<Link inline={true} size="small"><a href={'INSERT_URI'}>Link crumb</a></Link>,
<Link inline={true} size="small"><a href={'INSERT_URI'}>Link crumb</a></Link>,
<>
<span aria-hidden="true">Current crumb</span>
<span className="is-visually-hidden">Current page Current crumb</span>
</>
];
Actual rendering
const crumbs = {
items:
<Link inline={true} size="small"><a href={'INSERT_URI'}>Link crumb</a></Link>
<Link inline={true} size="small"><a href={'INSERT_URI'}>Link crumb</a></Link>
<Link inline={true} size="small"><a href={'INSERT_URI'}>Link crumb</a></Link>
<><span aria-hidden="true">Current crumb</span><span className="is-visually-hidden">Current page Current crumb</span></>
};
- Code Connect CLI version 1.1.3
- OSX Operating system
Thanks for the message Eric. Right now, there's no way to represent the children as an array. I brought it up to the team to discuss.
Curious, how do you imagine the API to support this, any preferred format that would feel "natural" to you?
@ptomas-figma first, thanks for asking!!!
Second, I realized a mistake in wrapping { items } when outside of the return statement, it should just be items. Still, that gets me to:
const crumbs =
<Link inline={true} size="small"><a href={'INSERT_URI'}>Link crumb</a></Link>
<Link inline={true} size="small"><a href={'INSERT_URI'}>Link crumb</a></Link>
<Link inline={true} size="small"><a href={'INSERT_URI'}>Link crumb</a></Link>
<><span aria-hidden="true">Current crumb</span><span className="is-visually-hidden">Current page Current crumb</span></>
;
As far as how, I think it would be nice if it was an optional parameter on figma.children. So, I could see my above code updating to something like:
items: figma.children(["_ ⚙️ Link crumb", "_ ✏️ Current crumb"], toArray),
or :
items: figma.children(["_ ⚙️ Link crumb", "_ ✏️ Current crumb"], "Array"),
or even something like:
items: figma.children(["_ ⚙️ Link crumb", "_ ✏️ Current crumb"], []),
That way, the manipulation is handled outside of the logic-less example.
Honestly, whatever makes the most sense to y'all. There are plenty of times where we hydrate our React components via a slot object. Another example of this is AvatarGroup, where we do:
<AvatarGroup items={[
{ text: 'AA' },
{ text: 'MD' },
{ text: 'PS'},
{ text: 'RD' }
]} />
So in that case, maybe figma.children allows for some interpolation? Something like:
items: items: figma.children(["_ ✏️ Avatar item"], [{
{
// with an enum for text, image, or icon returning the prop, like
// text: "AB"
// or
// icon: "user"
}
}]),
Thanks again Eric! Will circle this ideas back to the team for discussion.