-
Notifications
You must be signed in to change notification settings - Fork 4.3k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Allow multiple InnerBlocks per block #6808
Comments
@t-wright An alternative solution to the accordion block having multiple There is one caveat, though, and it is that the UI might be a bit tricky for something like a tabbed block. An accordion block would be easy to implement with the standard block UI, but a tabbed block sounds like something that may require special coding. So in the case of a tabbed container block, perhaps there is a need for the ability to have multiple |
Actually, now that I think about it, the tabbed block could probably be handled by having the block look different depending on whether or not it is selected. If unselected, the block would look pretty much like it does on the front-end, but when selected, each tab would appear as a block, all stacked vertically (like in any other container block). That is of course not the most ideal situation as it makes the block look different while it is being edited, but it does show that it is technically possible to have such a block in Gutenberg already. |
Thanks for giving this one some thought @SuperGeniusZeb. That's an approach I hadn't thought of and I think it makes sense. And getting re-ordering for free is a massive benefit too! I'll have a crack and see how I go. Ultimately I think the API and UI could be a more intuitive if multiple |
Multiple inner blocks have complexities that don't seem worth the effort, and in general it either hints at a block that should be broken down into multiple simpler blocks, or with block attributes (not children). Let us know how the above suggestion work for you and we could revisit. |
I am late on this topic but like to share one use case where multiple |
@emfluenceindia the way I've approached a similar problem is to create my own parent and child blocks. The parent block renders an The child block has an
|
I know probably there's some complexity to implement it, I think it can use the concept of named slots like all major javascript frameworks have. |
What would it take to get this issue opened back up? It seems like the dual answers of "it's too difficult for us to pull off" and "block developers can figure out workarounds with a combination of our template system and creating additional-sub blocks that serve no other purpose" are, at least on some level, a bit at odds with each-other. The use cases for multiple Inner Block sections are virtually endless. |
It's worth noting that some experimental enhancements to the InnerBlocks API have been made in #24232, allowing the children blocks to each be wrapped with a given set of markup, for example: <InnerBlocks
__experimentalItemCallback={ ( item ) => (
<>
<section>{ item }</section>
<p>You can do cool/weird stuff like this now.</p>
</>
) }
/> This is great for list-style blocks that want to wrap each child in a With these new API additions in mind, does anyone still think multiple Allowing blocks to have multiple Ultimately, what's wrong with using sub-blocks with their own If you have multiple content areas in a block, then conceptually, each of those areas are already a sort of "block" of content. So why not just actually use blocks for them? From a code quality perspective, that seems a lot better to me. Each sub-block would already have access to the usual APIs for allowed-children, templates, variations, and so on, because it's just a normal block. If you try to go the multiple So basically, I don't think using sub-blocks is a workaround; rather, I view it as the most logical solution when you're dealing with multiple sets of children. I think having multiple |
Agreed with @ZebulanStanphill. Multiple inner block areas add unnecessary complexity to the block API, grammar, and parsing logic and provide very little value over the existing setup. As mentioned before, intermediary blocks that are hidden from inserters can be used to handle more complex cases (like core's own Columns block) while preserving parsing unambiguity, which is an important architecture consideration for long term stability and performance. I also haven't seen concrete case articulated so far where multiple block areas would actually result in a better implementation compared to using the currently recommended mechanism. Perhaps we need more examples in the documentation that target the perceived need for multiple inner blocks? |
Just a simple question. How is this current accomplished with the multiple column layout block within WordPress? Just the fact that this exists seems to make me think there is a way to do it. |
"intermediary blocks that are hidden from inserters" |
Imagine something simple as this example... {
edit: () => {
return (
<section>
<aside>
<InnerBlocks name="sidebar"/>
</aside>
<div className="content">
<InnerBlocks />
</div>
</section>
);
},
save: () => {
return (
<section>
<aside>
<InnerBlocks.Content name="sidebar"/>
</aside>
<div className="content">
<InnerBlocks.Content />
</div>
</section>
);
},
} |
For now I'm solving with a Block Template. Which is fine, it works. I had to override some of the standard styles, and I suppress the add-new column option with CSS. I applied a grid style to Lucky for me, this isn't a public endeavor, so I can simply ask them not to do that.
|
The use case that brought me here is very similar to the example that @rodrigowbazevedo presented. Currently, if you want to have multiple blocks next to each other with the same parent element, it makes sense to have one However, this does not work when the child blocks are not siblings and represent different types of content. I am currently trying to build a block which is mostly static or editable using simple fields. There are two areas in this block where I would like the user to be able to add blocks like headings, paragraphs, and lists. One is a card-like element and the other is a full width area. These two areas are separated by other elements and do not share a parent element, so the solutions offered above would not work. Being able to target both of the areas with named |
+1 for this. Would be super powerful for creating multiple versions of a single block. Use cases would be translations, A/B testing etc |
Please re-open this. @willrowe has perfectly described the usecase. Named slots are really needed. |
@willrowe I have currently the same issue, I'm developing a Slider and as soon as I found out that I can only have one InnerBlock the whole project stopped, we really need this asap. I want also to be able to do this whiteout naming slots use-case: <div>
{[1, 2, 3, 4].map((slide, index) => (
<Slider key={slide}>
<InnerBlocks />
</Slider >
))}
</div> The user of my block should be able to add in each slide any block he wants, each slide should be able to have different InnerBlocks. |
@ivanjeremic you could check the Post Carousel that I’ve worked on, it might be helpful. Swiper is implemented behind the scenes, on the admin side as well as on the front-end side. |
This isn't really showing how to let the user add |
For the slider case, I'd suggest treating every "Slide" as a child block, restricted to your Slideshow parent, and each Slide containing a single inner blocks. |
I'm a bit confused with this because I thought InnerBlocks are child blocks how would an example of this kind of look like? Thanks. |
You'd have a It's essentially how |
So this means for an accordion block I'd get this tree view.
The custom/accordion-item-heading is nothing more than a static container block without any option, and just there to separate the core/heading from the other content. Same for the custom/accordion-item-content, but the other way around. This is in my experience a bit abusive to the tree view in the editor, but works fine besides that. |
@RuuddM not clear to me from the example why your |
Hello Gutenberg Team, I kindly request reconsideration for supporting multiple While the current approach makes perfect sense for blocks that require customizability (such as
By supporting multiple Thank you for your consideration and for your ongoing efforts to improve the platform. |
Hello @milanidavide! Do you have an example to review that shows such a case? In the years since inner blocks has existed we have not run across any examples that wouldn't be better if rethought around the idea of a single inner area, whether that is through custom intermediary blocks or more recently with locked groups and patterns. Single children makes the system a lot easier to reason with, debug, traverse, maintain, and perform. |
Hi Matias, Thank you for your prompt response and for considering the request. I understand the benefits of a single inner area from a maintenance perspective, and I agree that it can simplify the system in many cases. To illustrate the limitations of the current approach, let's consider a real-world example (see the attachment). Suppose we want to create a "reusable" section block that allows for customization throughout the site. This section consists of:
We also want to retain full control over the section's design, as it may change in the future, and we'd like to propagate those changes easily throughout the site. While we could break this down into multiple one-off blocks, create a template and lock it, I see several drawbacks with this approach:
By supporting multiple I'd appreciate your thoughts on this example. multiple-innerblocks-example.mp4 |
This made me smile. It's gradually becoming quite powerful, and I'm really looking forward to the upcoming pattern overrides. However, I still think some concerns haven't been fully addressed. Default blocks lack the fine-grained control needed for recreating "complex" designs, which is understandable. To overcome this, we need to break down the design into numerous single-use blocks that won't be reused elsewhere. This is a significant drawback for me as it complicates reasoning, maintenance, and largely extends development time. While it might be manageable for a one-time task, it really becomes burdensome when dealing with custom designs. I believe blocks would be really powerful if they allowed multiple blocks within a single unit. This is a common UI pattern in components, whether they are made in React, Vue, or even PHP functions. We could achieve more complex designs with better maintainability and much greater efficiency. I also have doubts about how patterns (with overrides) will behave when the pattern changes. If we decide to completely revamp the gallery's style, I guess all images would be lost. For instance, we currently have a carousel / grid, and let's assume we want to swap it with a different one. Additionally, I'm unsure if content-only editing will allow users to customize the overridable pattern (three points of access) on different pages with different blocks. It will address the intermediary blocks though, which will be hidden from the users. Edit: I've read some proposals related to the upcoming Synced Patterns Overrides and there seems to be a lot of overlap:
I would say that, while Synced Patterns Overrides and these proposals partially address my concerns, they still leave out some important ones. |
Why are you all so stuck on this single inner block thing? The very thing that made Wordpress popular in the first place was the developers didn't have to rethink what they wanted to do. Constantly having to rethink things through this obtuse restriction is not only counter to the advantages React brings in the first place, but I can't think of a single other system that uses this approach. WHAT is the advantage? |
"With a mix of these tools I think you can express the design above, and fill in the gaps with custom blocks as needed" Respectfully, that level of uncertainty for such a SIMPLE set of asks only further illustrates the point. |
@theaceofthespade Because it's a change with significant implications, they likely gave it much more thought than we did. However, raising concerns is important so we can find common ground |
Maybe more than you did, but I've been thinking about this for years, and project after project have validated that this approach makes no sense. I would accept that if they would stop trying to feed it to everyone like it's a feature or some positive choice that they made. "We can't figure it out" is a very different answer from "no this system is so much better, no one needs it!" So yes, if it's hard to do, they can own that and say "we're not capable" instead of trying to act like it's some ridiculous higher path or philosophical choice, because currently as far and wide as I search, there is no justification. |
Yeah development is hard sometimes. That's not the customers problem. |
@milanidavide ah, yes, I think we should split the conversation about custom blocks (because core blocks may not be sufficient to your case) from the single inner block area restriction. If there are specific things that you would have used a core block for but couldn't because it wasn't flexible, please, raise it as an issue and we can look into it. There's a balance between keeping core blocks simple and powerful for extenders. Even in your example about React children are not quite simple. It's one of the reasons why React supports fragments so you can express multiple children at the root. But notice it's still using a fragment in the tree to express it. It's not disimilar, in concept, to creating a mostly invisible custom block that doesn't show up in the inserter. Perhaps there needs to be a way to also make them invisible in the list view tree. Pattern overrides are designed precisely to propagate given the user content is stored outside the pattern, so as long as you are mapping the right names and attributes you can change the whole design. Give it ago if you can and if you run into complications, please, open issues! Not sure I follow the "three points of access" case, but they are overall created to improve upon the separation of content and presentation, so you can reuse designs across multiple pages and have localized content. How much is "content" is an ongoing process—for example, exposing more attributes of more blocks for editing. @theaceofthespade saying "no" to things is as much a part of the design process, but it's not a dogmatic refusal if through feedback and articulating use cases the stance changes. Single child support as direct nodes is a very common design pattern, not sure what you mean with it being counter given that React precisely only supports a single |
@mtias "Single child support as direct nodes is a very common design pattern, not sure what you mean with it being counter given that React precisely only supports a single props.children"
That's an absolute no-brainer in react with maybe a sprinkle of context or something at worst. But in Gutenberg it literally just doesn't work. Even pointing out that React offers fragments and similar as workarounds for this sort of problem should indicate to you that that's the direction to go. I'm not even just being sarcastic - I don't even know how you made it so that you can't have two of those and it feels like a code smell to me EDIT: Please note that I assume it is not, as I am not trying to insult you but rather communicate how counter that pattern feels to flux/react. |
@mtias Just to further emphasize this point about "not sure what you mean with it being counter given that React precisely only supports a single props.children." - If I put two inner blocks into a component, THEY'LL BOTH COME THROUGH THE CHILDREN PROP JUST FREAKING FINE. Now to meet you half way, And please note, all caps should be read as emphasis/or, if you prefer, Seinfeld like Larry David yelling. |
I do sincerely apologize for the broken up responses but I'm trying to provide more useful feedback as I get opportunities. It would make sense for the block templates/json to enforce structure rules that would be difficult to do in react (not that that isn't the case here), but as it is, things that would normally be possible to do in react require the use of a json-based templating language. It creates a huge limitation on the composing power of react components-as-template-parts. An actual technical reason |
Hello @mtias! Core blocks are great, personally, I believe they strike a good balance between power and complexity for non-technical users. I've been thinking about the upcoming synced patterns and the issues that I've linked in my previous answer:
Here's a rough sketch of a theme-synced pattern to illustrate these ideas: <!-- wp:element {"tag": "section", "className": "custom-section", "data-animate": "fade"} -->
<!-- wp:element {"tag": "div", "className": "custom-section__col-content", "data-animate": "fade-up"} -->
<!-- wp:group {"allowedBlocks": ["core/heading"], "metadata": {..., "name": "Eyebrow Headline"}} -->
... (optional headline)
<!-- /wp:group -->
<!-- wp:heading {"fontSize": "x-large", ...} -->
... (default title)
<!-- /wp:heading -->
<!-- wp:element {"tag": "div", "className": "custom-section__content", "data-animate": "fade-up"} -->
<!-- wp:group {"metadata": {"name": "Content"}} -->
... (optional content)
<!-- /wp:group -->
<!-- /wp:element -->
<!-- /wp:element -->
<!-- wp:element {"tag": "div", "className": "section__col-media", "data-animate": "fade-left"} -->
<!-- wp:group {"allowedBlocks": [...], "metadata": {..., "name": "..."}} -->
... (default block)
<!-- /wp:group -->
...
<!-- /wp:element -->
<!-- /wp:element --> Hopefully, this is not gibberish as I haven't had much opportunity to play around with patterns yet. I guess it's even possible to swap one block for another in the pattern (e.g. replace a gallery with another gallery) and maintain all the overrides since the binding is generic. You would still need some custom one-off blocks for specific features, such as the marquee animated text from the initial example, which would only work within this pattern. To better explain what I had in mind with multiple <section className="custom-section" data-animate="fade">
<div className="custom-section__col-content" data-animate="fade-up">
{/* Optional headline */}
<InnerBlocks slot="eyebrow-headline" name="Eyebrow Headline" />
{/* Default title */}
<RichText value="..." />
<div className="custom-section__content" data-animate="fade-up">
{/* Optional content */}
<InnerBlocks slot="content" name="Content" />
</div>
</div>
<div className="custom-section__col-media" data-animate="fade-left">
<InnerBlocks slot="..." name="..." />
{/* ... */}
</div>
</section> As for the title, a block like this one could also be responsible for the animated marquee text or other required parts. The editing experience could look something like this: |
@theaceofthespade I think you are confusing composition in general with children prop specifically. You are saying you don't want to use intermediary custom blocks for composition and that you want to leverage inner blocks multiple times directly. Inner blocks, however, functions like @milanidavide your wp:element suggestion is similar to an idea explored a few years ago with "transparent" blocks acting as wrapping nodes for the parser and block tree structure but being non visible and non interactive to the user. I think it's more likely now that group becomes that utility, which is what #61225 describes in part. There are intricacies in the user experience for invisible nodes—moving, copying, dragging, etc. In your example, the conceptual structure seems to be a single inner block area where you are passing a block tree made of a few custom blocks and some groups. Better ergonomics for passing a template like that to inner blocks would be good to improve. |
@mtias I think you're just misunderstanding separate concerns (totally my fault).
If I'm not mistaken we're just talking about the same thing from opposite directions here. I'm referring to the fact that the child prop receives multiple things from its parent through the child prop, whereas you're referring to the fact that each component only receives a single child (which is of course true). So to reiterate this comparison, the difference between passing things via the children prop in react vs any other component prop are pretty trivial - I am referring to the fact that what goes into the children prop is not restricted or particularly unique.
This makes no sense, because the component decides where the children are going. With multiple inner blocks the component would just be deciding (via whatever means) where multiple "children" are going. I would also argue that this is forcing state down into child components instead of lifting it up the tree the way React intends for you to do.
But the prop is not the problem; it's the restrictions that the child components put on the composition of the parent components. A key component of that children implementation in React is that the child components don't care what their parent is as long as they are fed the correct parameters, so that you can put whatever you want into the children prop (or any other prop). In terms of functional programming, you're ideally pushing toward pure functional components, and it is arguably an antipattern that using the same component twice in a row causes different outcomes.
This attitude is a problem - YOU don't get to tell me what I want, or what any of these other developers want. Or, rather, you can, but you need to listen when I tell you you're WRONG. This is quite literally you plugging your ears to complaints. I want to be able to build my layouts without thinking about it, placing components idempotently the way one quite literally does with all other react libraries, and I was never worried that it "would make the boundaries indistinguishable to parse between those areas" because that should be the case regardless. |
Sorry missed your follow up @theaceofthespade. I'm not sure if we are talking past each other, but just typing someone is WRONG in all caps is not the most eloquent argumentation path. You talk interchangeably about children being multiple things and I'm trying to say that it represents a single tree, regardless of where you place it. The way I interpret the requests are about declaring a transparent wrapper like #7694 (akin to react fragments) to avoid spurious container just to hold other blocks, not to multiple inner blocks / children props which is a whole different ordeal. That transparent wrapper is easy to conceptualize in the architecture of blocks, but it's not clear what the user experience should be as users navigate the block hierarchy or move things around. So that also needs an answer. |
How dare you, what else could you possibly have to do than talk to me, a relative stranger with virtually no stake?! I actually recently realized that other people do not see all caps as benign as I do, a mistake on my part (minus more aggressive language, i have always read it as a sort of emphasis rather than anything meant to intimidate or express anger, mostly because of the impotence of written communication). BUT in fairness, that "WRONG" was in the middle of a paragraph where I felt I was explaining why I thought you were wrong, and the emphasis was that unlike most of this, i believe this part is objective: you simply are not in a position to tell users what they do and do not want. You can at best suggest that you don't feel like that feature serves their expressed interests, but at the end of the day when a user tells you "that's not what I want," your opinion on the validity of that statement is entirely irrelevant. Presuming to tell users what they want is a great way to never hear it out (all that being said, I also understand that you're sometimes being put in a position to defend decisions, so I'm not trying to make blanket statements about this multi year thread). In a similar way, I think we are repeatedly branching the react children analogy conversation. I was making an initial point that I still do not believe is being fully understood, but also tried to address your disagreements (which is what i think you're picking up on in regard to me speaking interchangeably). Ie my point is not that your child prop assertions are necessarily WRONG (I couldn't resist), but rather that they are irrelevant to the point I was originally trying to communicate. So to emphasize my emphasis: in most react libraries and patterns I'm aware of, this sort of composition restriction very rarely exists, and the only examples I can think of are a direct result of some sort of pre-existing technical limitation (eg a wrapper for a dom manip library that only works on a page once, or certain meta tag react implementations). So I would reiterate that my intent was not to compare and contrast child prop implementations (not that i didn't do that), merely to communicate about this specific, nuanced dev-ex difference. I think 7694 potentially does address some of these if my initial read is correct (i'd take it over nothing) but I respectfully think you're still over thinking the request (game recognize game). Even before knowing exactly what the state access procedure would be, people expect to be able to freely compose their react components. Developers are coming to the "build in react" sign and expecting to be able to do all of it in react, the same way they would build anything else. I know because I've watched 4 different seasoned devs have the same experience on our team, and QUICKLY lose a lot of excitement for switching over. I believe people like myself are tripped up on this because they aren't used to working around this particular pattern/type of restriction on components, and it feels like Gutenberg limiting react instead of supercharging or extending it. I would go so far as to say it breaks the promise of letting you just build in react, especially when you must use a separate json file to accomplish things that feel (emphasis on feel) like they should be possible with a react library by itself. When you have a chance, if you could expound on those access concerns I would be happy to brainstorm/ try and suggest solutions. I am not implying I have all the answers or anything, merely that I can be more constructive than just complaining/criticizing if there are questions that need answers like that (even if only in a monkeys on typewriters sort of way). |
Not allowing multiple InnerBlocks per block is like not allowing named slots, other than default, which all template based approaches have (Native html web components, vue, react, svelte etc) |
@rodrigowbazevedo raised the same point 4 years ago and proposed a solution. Personally, I’ve stopped creating "specialized blocks" unless absolutely necessary. Slots play an important role in UI composition, it’s no coincidence that all those UI libs support them. |
Currently
InnerBlocks
can only be rendered once into any block.I can see there's been a lot of discussion around nested blocks so I'm sure there's a valid reason for this limitation but would be great to be able to be able to render multiple per block. The specific use case I'm thinking about is for a tabbed/accordion block with multiple content panes. Within each content pane you may want to have images or embeds etc.
This would be addressed in part by the inline blocks being discussed #2043 but allowing multiple
InnerBlocks
would provide more flexibility.The text was updated successfully, but these errors were encountered: