Toolbox

The toolbox is the side menu from whence the user may create new blocks. The structure of the toolbox is specified with either XML or JSON. This toolbox definition will be passed to Blockly when it is injected into the page.

XML

If using XML the toolbox can be created using either a tree of nodes, or a string representation. If you don't like typing XML manually, we recommend that you check out Blockly Developer Tools. With it, you can construct a toolbox and automatically generate its toolbox XML using a visual interface.

Here is a minimal example, using a tree of nodes:

<xml id="toolbox" style="display: none">
  <block type="controls_if"></block>
  <block type="controls_whileUntil"></block>
</xml>
<script>
  var workspace = Blockly.inject('blocklyDiv',
      {toolbox: document.getElementById('toolbox')});
</script>

Here is the same example, using a string representation:

<script>
  var toolbox = '<xml>';
  toolbox += '  <block type="controls_if"></block>';
  toolbox += '  <block type="controls_whileUntil"></block>';
  toolbox += '</xml>';
  var workspace = Blockly.inject('blocklyDiv', {toolbox: toolbox});
</script>

JSON

As of the September 2020 release toolboxes can also be defined using JSON.

Here is the same example as above, using JSON:

{
  "kind": "flyoutToolbox",
  "contents": [
    {
      "kind": "block",
      "type": "controls_if"
    },
    {
      "kind": "block",
      "type": "controls_whileUntil"
    }
  ]
}

All of the above examples create the same toolbox with two blocks:

If there are a small number of blocks, then they may be displayed without any categories (as in the minimal example above). In this simple mode all the available blocks are shown in the toolbox, there are no scrollbars on the main workspace, and the trashcan is not needed.

Categories

The blocks in the toolbox may be organized in categories. Here are two categories ('Control' and 'Logic'), each of which contain three blocks:

XML

<xml id="toolbox" style="display: none">
  <category name="Control">
    <block type="controls_if"></block>
    <block type="controls_whileUntil"></block>
    <block type="controls_for">
  </category>
  <category name="Logic">
    <block type="logic_compare"></block>
    <block type="logic_operation"></block>
    <block type="logic_boolean"></block>
  </category>
</xml>

JSON

{
  "kind": "categoryToolbox",
  "contents": [
    {
      "kind": "category",
      "name": "Control",
      "contents": [
        {
          "kind": "block",
          "type": "controls_if"
        },
        {
          "kind": "block",
          "type": "controls_whileUntil"
        },
        {
          "kind": "block",
          "type": "controls_for"
        }
      ]
    },
    {
      "kind": "category",
      "name": "Logic",
      "contents": [
        {
          "kind": "block",
          "type": "logic_compare"
        },
        {
          "kind": "block",
          "type": "logic_operation"
        },
        {
          "kind": "block",
          "type": "logic_boolean"
        }
      ]
    }
  ]
}

Below is the resulting toolbox, with the 'Logic' category clicked so that the three logic blocks in the flyout may be seen:

The presence of categories changes Blockly's UI to support larger applications. Scrollbars appear, allowing for an infinitely large workspace. A trashcan appears. Context menus contain more advanced options such as adding comments or collapsing blocks. All of these features may be overridden using the configuration options.

Accessing a category

A category can be retrieved from the toolbox using the category id. The category id can be set in the toolbox definition.

Setting the id for the category:

XML

<category name="..." toolboxitemid="categoryId"></category>

JSON

{
  "kind": "category",
  "name": "...",
  "toolboxitemid": "categoryId"
}

Accessing the category from the toolbox:

var category = toolbox.getToolboxItemById('categoryId');

Colours

Each category can be assigned a colour using the optional colour attribute. Note the British spelling. The colour is a number (0-360) defining the hue.

XML

<xml id="toolbox" style="display: none">
  <category name="Logic" colour="210">...</category>
  <category name="Loops" colour="120">...</category>
  <category name="Math" colour="230">...</category>
  <category name="Colour" colour="20">...</category>
  <category name="Variables" colour="330" custom="VARIABLE"></category>
  <category name="Functions" colour="290" custom="PROCEDURE"></category>
</xml>

JSON

{
  "contents": [
    {
      "kind": "category",
      "name": "Logic",
      "colour": "210"
    },
    {
      "kind": "category",
      "name": "Loops",
      "colour": "120"
    }
  ]
}

This colour appears as a rectangle to the left of the category, and as highlighting for the currently selected category:

Themes

If you have started using Blockly Themes then you will want to add the categorystyle attribute instead of the colour attribute as shown below.

XML

<category name="Logic" categorystyle="logic_category">
</category>

JSON

{
  "kind": "category",
  "name": "Logic",
  "categorystyle": "logic_category"
}

More information on Themes can be found here.

Category CSS

We provide a way through both the JSON and XML toolbox definitions to customize the different classes on a category. The following css classes can be changed.

  • container - The class for the parent div for the category. Default blocklyToolboxCategory.
  • row - The class for the div containing the category label and icon. Default blocklyTreeRow.
  • icon - The class for the category icon. Default blocklyTreeIcon.
  • label - The class for the category label. Default blocklyTreeLabel.
  • selected - The class that is added to the category when it is selected. Default blocklyTreeSelected.
  • openIcon - The class added to an icon when the category has nested categories and is open. Default blocklyTreeIconOpen.
  • closedIcon - The class added to an icon when the category has nested categories and is closed. Default blocklyTreeIconClosed.

Any of these can be set by using either XML or JSON. In XML simply prepend "css-" to one of the names above to change the class.

XML

<category name="..." css-container="yourClassName"></category>

JSON

{
  "kind": "category",
  "name": "...",
  "cssConfig": {
    "container": "yourClassName"
  }
}

Disabling a category

Disabling a category will not allow a user to click on the category and it will be skipped if a user is using the keyboard to navigate the toolbox. A CSS attribute is set on the blocklyToolboxCategory div that allows you to control the look of a disabled category as shown below.

var category = toolbox.getToolboxItems()[0];
category.setDisabled('true');
<style>
  .blocklyToolboxCategory[disabled="true"] {
    opacity: .5;
  }
</style>

Showing/Hiding a category

A category can be hidden when the toolbox is first injected, or it can be hidden later on through JavaScript.

XML

<category name="..." hidden="true"></category>

JSON

{
  "kind": "category",
  "name": "...",
  "hidden": "true"
}

JavaScript

var category = toolbox.getToolboxItems()[0];
category.hide();

Dynamic categories

There are two categories that have special behaviours. Variable and function categories are defined with no contents, but with a 'custom' property of 'VARIABLE' or 'PROCEDURE' respectively. These categories will be populated automatically with the appropriate blocks.

XML

<category name="Variables" custom="VARIABLE"></category>
<category name="Functions" custom="PROCEDURE"></category>

JSON

{
  "kind": "category",
  "name": "Variables",
  "custom": "VARIABLE"
},
{
  "kind": "category",
  "name": "Functions",
  "custom": "PROCEDURE"
}

Note: The word 'procedure' is used throughout the Blockly codebase, but the word 'function' has since been found to be more understandable by students. Sorry for the mismatch.

Developers may also use the custom property to create dynamically populated flyout categories. For example, to create a flyout with a custom set of colour blocks:

  • Create a category with a custom property.

    <category name="Colours" custom="COLOUR_PALETTE"></category>
    
  • Define a callback to provide the category contents. This callback should take in a workspace and return an array of XML block elements.

    /**
     * Construct the blocks required by the flyout for the colours category.
     * @param {!Blockly.Workspace} workspace The workspace this flyout is for.
     * @return {!Array.<!Element>} Array of XML block elements.
     */
    myApplication.coloursFlyoutCallback = function(workspace) {
      // Returns an array of hex colours, e.g. ['#4286f4', '#ef0447']
      var colourList = myApplication.getPalette();
      var xmlList = [];
      if (Blockly.Blocks['colour_picker']) {
        for (var i = 0; i < colourList.length; i++) {
          var blockText = '<block type="colour_picker">' +
              '<field name="COLOUR">' + colourList[i] + '</field>' +
              '</block>';
          var block = Blockly.Xml.textToDom(blockText);
          xmlList.push(block);
        }
      }
      return xmlList;
    };
    
  • Register the callback on the workspace.

    myWorkspace.registerToolboxCategoryCallback(
      'COLOUR_PALETTE', myApplication.coloursFlyoutCallback);
    

Typed Variables

If you are using typed variables you will need to add variabletype to your variable fields.

<block type="vars_set">
  <field name="VAR_SET" variabletype="panda"></field>
</block>

Tree of Categories

Categories may be nested within other categories. Here are two top-level categories ('Core' and 'Custom'), each of which contain two sub-categories, each of which contain blocks:

XML

<xml id="toolbox" style="display: none">
  <category name="Core">
    <category name="Control">
      <block type="controls_if"></block>
      <block type="controls_whileUntil"></block>
    </category>
    <category name="Logic">
      <block type="logic_compare"></block>
      <block type="logic_operation"></block>
      <block type="logic_boolean"></block>
    </category>
  </category>
  <category name="Custom">
    <block type="start"></block>
    <category name="Move">
      <block type="move_forward"></block>
      <block type="move_backward"></block>
    </category>
    <category name="Turn">
      <block type="turn_left"></block>
      <block type="turn_right"></block>
    </category>
  </category>
</xml>

JSON

{
  "kind": "categoryToolbox",
  "contents": [
    {
      "kind": "category",
      "name": "Core",
      "contents": [
        {
          "kind": "category",
          "name": "Control",
          "contents": [
            {
              "kind": "block",
              "type": "controls_if"
            },
            {
              "kind": "block",
              "type": "controls_whileUntil"
            }
          ]
        },
        {
          "kind": "category",
          "name": "Logic",
          "contents": [
            {
              "kind": "block",
              "type": "logic_compare"
            },
            {
              "kind": "block",
              "type": "logic_operation"
            },
            {
              "kind": "block",
              "type": "logic_boolean"
            }
          ]
        }
      ]
    },
    {
      "kind": "category",
      "name": "Custom",
      "contents": [
        {
          "kind": "block",
          "type": "start"
        },
        {
          "kind": "category",
          "name": "Move",
          "contents": [
            {
              "kind": "block",
              "type": "move_forward"
            },
            {
              "kind": "block",
              "type": "move_backward"
            }
          ]
        },
        {
          "kind": "category",
          "name": "Turn",
          "contents": [
            {
              "kind": "block",
              "type": "turn_left"
            },
            {
              "kind": "block",
              "type": "turn_right"
            }
          ]
        }
      ]
    }
  ]
}

Note that it is possible for a category to contain both sub-categories and blocks. In the above example, 'Custom' has two sub-categories ('Move' and 'Turn'), as well as a block of its own ('start').

Expanded

Categories are shown collapsed by default when Blockly is loaded, but a category may be expanded with

XML

<category name="..." expanded="true"></sep>

JSON

{
  "kind": "category",
  "name": "...",
  "expanded": "true"
}

Preset Blocks

The toolbox definition may contain blocks that have fields set to a default value, or have blocks that are already connected together.

Here are four blocks:

  1. A simple logic_boolean block with no preset values:
  2. A math_number block that has been modified to display the number 42 instead of the default of 0:
  3. A controls_for block that has three math_number blocks connected to it:
  4. A math_arithmetic block that has two math_number shadow blocks connected to it:

Here is the code to generate these four blocks in a toolbox using XML:

<xml id="toolbox" style="display: none">
  <block type="logic_boolean"></block>

  <block type="math_number">
    <field name="NUM">42</field>
  </block>

  <block type="controls_for">
    <value name="FROM">
      <block type="math_number">
        <field name="NUM">1</field>
      </block>
    </value>
    <value name="TO">
      <block type="math_number">
        <field name="NUM">10</field>
      </block>
    </value>
    <value name="BY">
      <block type="math_number">
        <field name="NUM">1</field>
      </block>
    </value>
  </block>

  <block type="math_arithmetic">
    <field name="OP">ADD</field>
    <value name="A">
      <shadow type="math_number">
        <field name="NUM">1</field>
      </shadow>
    </value>
    <value name="B">
      <shadow type="math_number">
        <field name="NUM">1</field>
      </shadow>
    </value>
  </block>
</xml>

The XML for these preset or connected blocks is the same as Blockly's XML save format. Thus, the easiest way to construct the XML for such blocks is to use the Code application to build the blocks, then switch to the XML tab and copy the result. The x, y, and id properties are ignored by the toolbox and may be stripped out.

JSON

Preset blocks and connected blocks can be specificed in JSON using the blockxml attribute. For more information on what the XML string should be check the above section.

{
  "kind": "block",
  "blockxml": "<block type='math_number'><field name='NUM'>42</field></block>"
}

This is only necessary if you are changing a field value or connecting blocks together. If you do not need to do either of the above actions you can simply use type.

{
  "kind": "block",
  "type": "math_number"
}

Shadow blocks

Shadow blocks are placeholder blocks that perform several functions:

  • They indicate the default values for their parent block.
  • They allow users to type values directly without needing to fetch a number or string block.
  • Unlike a regular block, they get replaced if the user drops a block on top of them.
  • They inform the user of the type of value expected.

Shadow blocks cannot be constructed with the Code application directly. Instead one can use regular blocks, then change <block ...> and </block> in the XML to <shadow ...> and </shadow>.

Variables

Most fields are easy to set in your toolbox, needing only a name attribute and their value.

<field name="NUM">1</field>

Variables, however, have additional optional attributes which affect how they are created. A variable field can have an id and a variabletype. Note that variabletype does not use camelCase.

<field name="VAR" id=".n*OKd.u}2UD9QFicbEX" variabletype="Panda">Bai Yun</field>

If an id is set then the variabletype (if set) and the value must match any existing variable with that id when the block is created. If no variable with that id exists a new variable will be created. In general, the id should not be included in your toolbox XML. Omitting the id allows the variable to refer to an existing variable if it has the same value and variabletype.

If a variabletype is set the variable will be created with that type. If variabletype is not set the variable will have the default '' type. The variabletype must be set if you are using typed variables, as Blockly will not infer the type.

→ For more information, see Variable Fields.

Separators

Adding a separator between any two categories will create a line and extra space between the two categories.

You can change the class for the separator in your JSON or XML toolbox definition.

XML

<sep css-container="yourClassName"></sep>

JSON

{
  "kind": "sep",
  "cssConfig": {
    "container": "yourClassName"
  }
}

Adding a separator between any two blocks will create a gap between the blocks. By default every block is separated from its lower neighbour by 24 pixels. This separation may be changed using the 'gap' attribute, which will replace the default gap.

XML

<xml id="toolbox" style="display: none">
  <block type="math_number"></block>
  <sep gap="32"></sep>
  <block type="math_arithmetic">
    <field name="OP">ADD</field>
  </block>
  <sep gap="8"></sep>
  <block type="math_arithmetic">
    <field name="OP">MINUS</field>
  </block>
</xml>

JSON

{
  "kind": "flyoutToolbox",
  "contents": [
    {
      "kind": "block",
      "type":"math_number"
    },
    {
      "kind": "sep",
      "gap": "32"
    },
    {
      "kind": "block",
      "blockxml": "<block type='math_arithmetic'><field name='OP'>ADD</field></block>"
    },
    {
      "kind": "sep",
      "gap": "8"
    },
    {
      "kind": "block",
      "blockxml": "<block type='math_arithmetic'><field name='OP'>MINUS</field></block>"
    }
  ]
}

Adjusting the gaps between blocks allows one to create logical groups of blocks in the toolbox.

Buttons and Labels

You can put a button or label anywhere you can put a block in the toolbox.

XML

<xml id="toolbox" style="display: none">
  <block type="logic_operation"></block>
  <label text="A label" web-class="myLabelStyle"></label>
  <label text="Another label"></label>
  <block type="logic_negate"></block>
  <button text="A button" callbackKey="myFirstButtonPressed"></button>
  <block type="logic_boolean"></block>
</xml>

JSON

{
  "kind": "flyoutToolbox",
  "contents": [
    {
      "kind": "block",
      "type":"logic_operation"
    },
    {
      "kind": "label",
      "text": "A label",
      "web-class": "myLabelStyle"
    },
    {
      "kind": "label",
      "text": "Another label"
    },
    {
      "kind": "block",
      "type": "logic_negate"
    },
    {
      "kind": "button",
      "text": "A button",
      "callbackKey": "myFirstButtonPressed"
    },
    {
      "kind": "block",
      "type": "logic_boolean"
    }
  ]
}
    <style>
    .myLabelStyle>.blocklyFlyoutLabelText {
      font-style: italic;
      fill: green;
    }
    </style>

You may specify a CSS class name to apply to your button or label. In the above example, the first label uses a custom style, while the second label uses the default style.

Buttons should have callback functions; labels should not. To set the callback for a given button click, use

yourWorkspace.registerButtonCallback(yourCallbackKey, yourFunction).

Your function should accept as an argument the button that was clicked. The "Create variable..." button in the variable category is a good example of a button with a callback.

Disabled

Blocks in a toolbox may be individually disabled using the optional disabled attribute:

XML

<xml id="toolbox" style="display: none">
  <block type="math_number"></block>
  <block type="math_arithmetic"></block>
  <block type="math_single" disabled="true"></block>
</xml>

JSON

{
  "kind": "flyoutToolbox",
  "contents": [
    {
      "kind": "block",
      "type":"math_number"
    },
    {
      "kind": "block",
      "type": "math_arithmetic"
    },
    {
      "kind": "block",
      "type": "math_single",
      "disabled": "true"
    }
  ]
}

Disabling blocks may be used to restrict the user's choices. Perhaps advanced blocks might be unlocked after certain achievements.

You can programmatically disable or enable a block by using setEnabled.

Blockly.selected.setEnabled(true);

Changing the Toolbox

The application may change the blocks available in the toolbox at any time with a single function call:

workspace.updateToolbox(newTree);

As was the case during initial configuration, newTree may either be a tree of nodes, a string representation, or a JSON object. The only restriction is that the mode cannot be changed; that is if there were categories in the initially-defined toolbox then the new toolbox must also have categories (though the categories may change). Likewise, if the initially-defined toolbox did not have any categories, then the new toolbox may not have any categories.

The contents of a single category can be updated by:

var category = toolbox.getToolboxItems()[0];
category.updateFlyoutContents(flyoutContents);

Where flyoutContents can be a list of blocks defined using JSON, a tree of nodes, or a string representation.

Be aware that at this time updating the toolbox causes some minor UI resets:

  • In a toolbox without categories, any fields changed by the user (such as a dropdown) will revert to the default.

Here is a live demo of a tree with categories and block groups.