1

When I click a button to add a new tab, I would like to have an <InnerBlock /> so I can add other blocks within the tab. Trying this does not work as the same seems to be in all the dynamically created tabs.

import "./index.css";
import { registerBlockType } from "@wordpress/blocks";
import { useState } from "react";
import {
  RichText,
  InnerBlocks,
} from "@wordpress/block-editor";
import { Button } from "@wordpress/components";
const __ = wp.i18n.__;

registerBlockType("custom/tabs", {
  title: __("Tabbed Blocks", "custom-blocks"),
  description: __("Tabbed content blocks", "custom-blocks"),
  icon: "smiley",
  category: "custom-category",
  keywords: [__("tabs", "custom-blocks"), __("repeat", "custom-blocks")],
  attributes: {
    tabs: {
      type: "array",
      default: [""],
    },
  },

  edit: (props) => {
    const {
      attributes: { tabs },
      setAttributes,
    } = props;

    const [currentTab, setCurrentTab] = useState(0);

    const onTabClick = (index) => {
      setCurrentTab(index);
    };

    return (
      <>
        <div className="simple-tabs">
          <div className="tabs">
            {tabs.map((tab, index) => (
              <RichText
                tagName="button"
                value={tab}
                className={currentTab == index ? `active` : ""}
                onChange={(newValue) => {
                  const newTabs = tabs.concat([]);
                  newTabs[index] = newValue;
                  setAttributes({ tabs: newTabs });
                }}
                onClick={() => onTabClick(index)}
              />
            ))}
          </div>

          {tabs.map((tab, index) => {
            if (index == currentTab) {
              //return <div>Tab content {index}</div>;
              return <InnerBlocks />;
            }
          })}
        </div>
        <Button
          isPrimary
          onClick={() => {
            setAttributes({ tabs: tabs.concat([""]) });
          }}
        >
          Add Tab
        </Button>
      </>
    );
  },
  save: (props) => {
   return <InnerBlocks.Content />;
  },
});

Desired output

enter image description here

enter image description here

1 Answer 1

2

You don't

That's not how blocks work, and it's not how HTML works. If you want multiple areas to insert blocks into, you need multiple blocks.

This is the same as saying that a box has multiple insides, or that there is more than one "inside a HTML tag", it does not make sense as a concept.

Instead, do what the official core blocks do. E.g Columns.

  • Columns block
    • column
      • paragraph
      • paragraph
    • column
      • paragraph
      • paragraph

A columns block can only contain individual column blocks, and it's the individual column blocks that contain the content.

enter image description here

Tabs would work the same:

  • Tabs
    • tab
      • paragraph
      • paragraph
    • tab
      • paragraph
      • paragraph

Notice as well that what you're asking for is also not possible to represent in bullet points without accidentally coming up with the exact same solution.

It's the same with HTML tags, if I want to have a <div> container with 2 internal spaces I have to put 2 tags inside it to act as the separate spaces. Why would blocks be any different.

Note that the block appender UI is just the default UI, and nothing prevents you passing a custom appender component to the inner blocks UI, or even building one into the block itself.

Here's an example taken straight from the readme for the InnerBlocks components appender attribute doc:

// Utilise a predefined component
<InnerBlocks
    renderAppender={ InnerBlocks.ButtonBlockAppender }
/>

// Don't display an appender
<InnerBlocks
    renderAppender={ false }
/>

// Fully custom
<InnerBlocks
    renderAppender={ MyAmazingAppender }
/>

Here's an appender component:

function render( { clientId } ) {
    return (
        <div>
            <p>Some rendered content here</p>
            <ButtonBlockAppender rootClientId={ clientId } />
        </div>
    );
}

https://github.com/WordPress/gutenberg/tree/trunk/packages/block-editor/src/components/button-block-appender

Here is how the tabs block from ultimate GB addons does it:

        const { insertBlock } = !wp.blockEditor ? dispatch( 'core/editor' ) : dispatch( 'core/block-editor' );
        const tabItemBlock = createBlock('uagb/tabs-child');

        insertBlock(tabItemBlock, attributes.tabHeaders.length, clientId);

Here they use a uaggb/tabs block to provide the UI and contain the tabs, and a uaggb/tabs-child block to contain the content of each tab and provide tab specific attributes

Useful links:

7
  • I included notes on the appender based on your previous question. You need to approach this step by step, don't throw out the correct next step because you cannot see how you will make the final two steps, you can always ask new questions!
    – Tom J Nowell
    Nov 23, 2021 at 19:55
  • Thanks Tom, I will go through this in detail later when I get a gap. You may have addressed everything as I haven't had chance to read it yet but I just attached two images from another plugin I installed to show you what I mean. They are doing exactly what I am trying to do in that you can add more tabs within the same block and then add InnerBlocks into each tab. I don't have to add a new tab block for each tab. Nov 24, 2021 at 6:26
  • If you want to see a working demo of the tabs in my screenshot you can just download the free plugin to see ultimategutenberg.com Nov 24, 2021 at 6:36
  • 1
    that's exactly what you need to do, you're on the right track! It'll show them in a vertical list and give you a default appender, you can replace the appender with your own, the listing the tabs part is a little less common of a task so that'd actually make a great next question to ask. Showing the current tab sounds like a great excuse to make use of the context API. When you open the next question drop a link here :) A tabs block is a little more complex than what most people build, but once you've done it you'll be in a great position
    – Tom J Nowell
    Nov 24, 2021 at 15:39
  • 1
    Hey Tom, I added a new question and here is the link :) I can only hope I am on the right track. wordpress.stackexchange.com/questions/398509/… Nov 24, 2021 at 17:50

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.