# Technical Documentation: RaspberryPiFoundation/blockly

> ℹ️ **Provenance:** Multi-Tier Ingestion · [CodeWiki Reference](https://codewiki.google/github.com/RaspberryPiFoundation/blockly)

### Overview (README.md)

# Blockly

Blockly is a library that adds a visual code editor to web apps. The Blockly editor uses interlocking, graphical blocks to represent code concepts like variables, logical expressions, loops, and more. It allows users to apply programming principles without having to worry about syntax or the intimidation of a blinking cursor on the command line. All code is [free and open source](https://github.com/raspberrypifoundation/blockly/blob/develop/LICENSE).



## Getting Started with Blockly

Blockly has many resources for learning how to use the library. You can [try a live demo](https://raspberrypifoundation.github.io/blockly/packages/blockly/demos/code/index.html) or [visit our developer site](https://docs.blockly.com) to read the documentation on how to get started, configure Blockly, and integrate it into your application. The developer site also contains links to:

- [Getting Started article](https://docs.blockly.com/guides/get-started/what-is-blockly/)
- [Getting Started codelab](https://docs.blockly.com/codelabs/getting-started/codelab-overview/)
- [More codelabs](https://docs.blockly.com/codelabs/)
- [Demos and plugins](https://raspberrypifoundation.github.io/blockly-samples/)

### Installing Blockly

If you're starting a new project using Blockly, you can bootstrap it
using our [`create-package` tool](https://www.npmjs.com/package/@blockly/create-package):

```bash
npx @blockly/create-package app my-cool-blockly-app --typescript
```

Or, if you're adding Blockly to an existing project, just [install it with npm](https://www.npmjs.com/package/blockly):

```bash
npm install blockly
```

### Getting Help

- [Report a bug](https://docs.blockly.com/guides/contribute/get-started/write_a_good_issue/) or file a feature request on GitHub
- Ask a question, or search others' questions, on our [developer forum](https://groups.google.com/forum/#!forum/blockly). You can also drop by to say hello and show us your prototypes; collectively we have a lot of experience and can offer hints which will save you time. We actively monitor the forums and typically respond to questions within 2 working days.

### blockly-samples

We have a number of [examples](https://github.com/raspberrypifoundation/blockly-samples/tree/main/examples) which demonstrate various techniques to include and extend the Blockly library. These examples can be found in another repository called [blockly-samples](https://github.com/raspberrypifoundation/blockly-samples).

### Plugins

A plugin is a self-contained piece of code that adds functionality to Blockly. Plugins can add fields, define themes, create renderers, and much more. For more information, see the [Plugins documentation](https://docs.blockly.com/guides/programming/plugin_overview/).

## Contributing to Blockly

Want to make Blockly better? We welcome contributions to Blockly in the form of pull requests, bug reports, documentation, answers on the forum, and more! Check out our [Contributing Guidelines](https://docs.blockly.com/guides/contribute/) for more information. You might also want to look for issues tagged "[Help Wanted](https://github.com/raspberrypifoundation/blockly/labels/help%20wanted)" which are issues we think would be great for external contributors to help with.

## Releases

We release new versions on npm and GitHub releases, and then update our [docs](https://docs.blockly.com) and [demo pages](https://raspberrypifoundation.github.io/blockly-samples/). If there are breaking regressions, such as a crash when performing a standard action or a rendering issue that makes Blockly unusable, we will cherry-pick fixes into patch releases. The [releases page](https://github.com/raspberrypifoundation/blockly/releases) has a list of all releases.

We use [semantic versioning](https://semver.org/). Releases that have breaking changes or are otherwise not backwards compatible will have a new major version. Patch versions are reserved for bug-fix patches between scheduled releases.

We now have a [beta release on npm](https://www.npmjs.com/package/blockly?activeTab=versions). If you'd like to test the upcoming release, or try out a not-yet-released new API, you can use the beta channel with:

```bash
npm install blockly@beta
```

As it is a beta channel, it may be less stable, and the APIs there are subject to change.

### Branches

Most development happens in the **[main](https://github.com/raspberrypifoundation/blockly/tree/main)** branch. Pull requests should typically be made against main. This branch should be stable; features that aren't ready yet should be merged to a feature branch instead. Once something is in main we expect it to be part of the next release. However, features and APIs here are subject to change until they are released. If you're working on a production application using Blockly, you should use the release from npm or the GitHub release page, not the `main` branch.

Larger changes may have their own branches until they are good enough for people to try out. These will be developed separately until we think they are almost ready for release. They will be merged into main when ready.

### New APIs

Once a new API is released, it is considered beta until the following release. We generally try to avoid changing an API after it has been released, but sometimes we need to make changes after seeing how an API is used. If an API has been around for at least two releases we'll do our best to avoid breaking it.

Unreleased APIs may change radically. Anything that is in `main` but not released is subject to change without warning.

## Issues and Milestones

We typically triage all bugs within 1 week, which includes adding any appropriate labels and assigning it to a milestone. Please keep in mind, we are a small team so even feature requests that everyone agrees on may not be prioritized.

## Accessibility

Although Blockly is built around drag-and-drop, it is fully usable with the
keyboard alone. Blockly is also accessible to screenreader users by default. We
provide [Accessibility Conformance Reports](https://docs.blockly.com/guides/app-integration/accessibility/compliance/)
in the VPAT format that outline Blockly's conformance to WCAG 2.2 Level AA.

---

### Packages Docs README (`packages/docs/README.md`)

# Blockly Documentation Website

This website is built using [Docusaurus](https://docusaurus.io/), a modern static website generator.

## Installation

Run `npm install` at the root of the blockly repo, then all other commands from the `packages/docs` directory.

```bash
npm install
cd packages/docs
```

## Local development

```bash
npm start
```

This command starts a local development server and opens up a browser window. Most changes are reflected live without having to restart the server.

## Build

```bash
npm run build
```

This command generates static content into the `build` directory and can be served using any static contents hosting service.

## Test your build locally

```bash
npm run serve
```

The build folder is now served at http://localhost:3000/

## Formatting and linting

```bash
# check formatting:
npm run format-check
# fix formatting:
npm run format
# check linting:
npm run lint
# fix linting:
npm run lint-fix
```

Prettier is used for formatting JavaScript files (the `format` script).

ESlint is used for linting `.md` and `.mdx` files due to poor support for these in Prettier (the `lint` script).

## Generating reference docs

The API reference pages are auto-generated from the Blockly TypeScript source 
using [TypeDoc](https://www.npmjs.com/package/typedoc). Typedoc automatically 
generates MDX files into `/docs/reference/` when Docusaurus starts.

TypeDoc generates the API docs based on the latest Blockly release, not the 
current code. If you would like to see unreleased or beta changes reflected 
in your local docs site, run `npm run reference:refresh`. This will overwrite a 
file called `blockly_api.json` which TypeDoc uses to generate the docs. Then, 
you can run docs again to see updates to the API docs. 

If you regenerate `blockly_api.json`, please do not commit it in a PR. This 
file is committed automatically as part of our release process.

---

### Packages Docs Docs Codelabs Index (`packages/docs/docs/codelabs/index.mdx`)

---
title: Welcome to the Blockly Codelabs
pagination_next: null
pagination_prev: null
---

import { CodelabGrid, CodelabCard } from '@site/src/components/CodelabCards';
import Image from '@site/src/components/Image';

Blockly Codelabs provide a guided, tutorial, hands-on coding experience of Blockly.

<CodelabGrid>
  <CodelabCard
    level="beginner"
    title="Getting started with Blockly"
    href="/codelabs/getting-started/codelab-overview">
    <Image
      alt="Loop block with 'Add text' block that takes the string 'Blockly' as an input" 
      src="/images/codelabs/card_thumbnails_getting-started.png"
      srcDark="/images/codelabs/card_thumbnails_getting-started-dark.png"
    />
  </CodelabCard>
  <CodelabCard
    level="beginner"
    title="Customizing a Blockly toolbox"
    href="/codelabs/custom-toolbox/codelab-overview">
    <Image
      alt="A list of different colour categories labeled 'Logic', 'Loops', 'Math', and 'Text' with the label 'Custom Toolbox'"
      src="/images/codelabs/card_thumbnails_blockly-toolbox.png"
      srcDark="/images/codelabs/card_thumbnails_blockly-toolbox-dark.png"
    />
  </CodelabCard>
  <CodelabCard
    level="beginner"
    title="Customizing your themes"
    href="/codelabs/theme-extension-identifier/codelab-overview">
    <Image
      alt="An addition block with shadow blocks and labels pointing out block colour, shadow block colour, and border colour"
      src="/images/codelabs/card_thumbnails_themes.png"
      srcDark="/images/codelabs/card_thumbnails_themes-dark.png"
    />
  </CodelabCard>
  <CodelabCard
    level="Intermediate"
    title="Customizing context menus"
    href="/codelabs/context-menu-option/codelab-overview">
    <Image
      alt="An if do block with a context menu that displays options 'Duplicate', 'Add Comment', and 'Inline Inputs'"
      src="/images/codelabs/card_thumbnails_context-menus.png"
      srcDark="/images/codelabs/card_thumbnails_context-menus-dark.png"
    />
  </CodelabCard>
  <CodelabCard
    level="Intermediate"
    title="Block validation and warnings"
    href="/codelabs/validation-and-warnings/codelab-overview">
    <Image
      alt="Two list blocks: one is attached to a print block and creates a list of numbers 0 to 5, another creates a list with numbers from 6 to 3 and is grayed out with a warning icon"
      src="/images/codelabs/card_thumbnails_validating-and-displaying.png"
      srcDark="/images/codelabs/card_thumbnails_validating-and-displaying-dark.png"
    />
  </CodelabCard>
  <CodelabCard
    level="Intermediate"
    title="Use CSS in Blockly"
    href="/codelabs/css/codelab-overview">
    <Image
      alt="An if do block where the if input is true and the do input sets border radius to 24"
      src="/images/codelabs/card_thumbnails_css.png"
      srcDark="/images/codelabs/card_thumbnails_css-dark.png"
    />
  </CodelabCard>
  <CodelabCard
    level="Advanced"
    title="Build a custom generator"
    href="/codelabs/custom-generator/codelab-overview">
    <Image
      alt="A create list block with four inputs: the number one, the string 'two', boolean false, and boolean true"
      src="/images/codelabs/card_thumbnails_custom-generator.png"
      srcDark="/images/codelabs/card_thumbnails_custom-generator-dark.png"
    />
  </CodelabCard>
  <CodelabCard
    level="Advanced"
    title="Build custom renderers"
    href="/codelabs/custom-renderer/codelab-overview">
    <Image
      alt="A repeat 10 times loop block"
      src="/images/codelabs/card_thumbnails_custom-renderers.png"
      srcDark="/images/codelabs/card_thumbnails_custom-renderers-dark.png"
    />
  </CodelabCard>
  <CodelabCard
    level="Advanced"
    title="Build a custom mutator"
    href="/codelabs/custom-mutator/codelab-overview">
    <Image
      alt="Two 'resizable list with' blocks: the first with two filled inputs, the second with the same two filled inputs and an empty third input"
      src="/images/codelabs/card_thumbnails_custom-mutator.png"
      srcDark="/images/codelabs/card_thumbnails_custom-mutator-dark.png"
    />
  </CodelabCard>
</CodelabGrid>

---

### Packages Docs Docs Codelabs Context Menu Option Codelab Overview (`packages/docs/docs/codelabs/context-menu-option/codelab-overview.mdx`)

---
pagination_prev: null
description: Overview of the "Customizing context menus" codelab.
---

# Customizing context menus

## 1. Codelab overview

### What you'll learn

In this codelab you will learn how to:

- Add a context menu option to the workspace.
- Add a context menu option to all blocks.
- Use precondition functions to hide or disable context menu options.
- Take an action when a menu option is selected.
- Customize ordering and display text for context menu options.

### What you'll build

A very simple Blockly workspace with a few new context menu options.

### What you'll need

- A browser.
- A text editor.
- Basic knowledge of HTML, CSS, and JavaScript.
- node.js and npm installed ([instructions](https://docs.npmjs.com/downloading-and-installing-node-js-and-npm)).
- Comfort using the command line/terminal.

You can find the code for the [completed context menu codelab](https://github.com/RaspberryPiFoundation/blockly/tree/main/packages/docs/docs/codelabs/context-menu-option/complete-code) on GitHub.

This codelab is focused on Blockly's context menus. Non-relevant concepts and code are glossed over and are provided for you to simply copy and paste.

---

### Packages Docs Docs Codelabs Css Codelab Overview (`packages/docs/docs/codelabs/css/codelab-overview.mdx`)

---
pagination_prev: null
description: Overview of the "Use CSS in Blockly" codelab.
---

import Image from '@site/src/components/Image';

# Use CSS in Blockly

## 1. Codelab overview

### What you'll learn

In this codelab you will learn how to use CSS to customize the colours of:

- Components
- Categories
- Blocks

If you don't need the fine-grained control provided by CSS, consider using
themes instead. For more information, see the
[Customizing your themes](/codelabs/theme-extension-identifier/codelab-overview)
codelab.

### What you'll build

A simple Blockly workspace that uses the same Halloween colours as the [Customizing your themes](/codelabs/theme-extension-identifier/codelab-overview) codelab.

<Image
  src="/images/codelabs/css/final-workspace.png"
  alt="A Blockly editor in Halloween colors, the logic flyout open and various blocks on the workspace. The code and output divs are still the default colors."
  className="codelabImage"
/>

You can find the code for the [completed CSS codelab](https://github.com/RaspberryPiFoundation/blockly/tree/main/packages/docs/docs/codelabs/css/complete-code) on GitHub.

### What you'll need

- A browser.
- A text editor.
- Basic knowledge of HTML, CSS, SVG, and JavaScript.
- Basic knowledge of your browser's developer tools.
- node.js and npm installed ([instructions](https://docs.npmjs.com/downloading-and-installing-node-js-and-npm)).
- Comfort using the command line/terminal.
- Basic understanding of Blockly, including workspace components, category toolboxes, block definitions, and themes.

This codelab is focused on using CSS with Blockly. Non-relevant concepts are glossed over and provided for you to simply copy and paste.

---

### Packages Docs Docs Codelabs Custom Generator Block Generator Overview (`packages/docs/docs/codelabs/custom-generator/block-generator-overview.mdx`)

---
description: Introduction to block generators.
---

# Build a custom generator

## 4. Block generator overview

At its core, a block generator is a function that takes in a block (and optionally the language generator instance), translates the block into code, and returns that code as a string.

Each language generator has a property called `forBlock`, which is a dictionary object where all block generator functions must be placed. For instance, here is the code to add a block generator for blocks of type `sample_block` on a language generator object (`sampleGenerator`).

```js
sampleGenerator.forBlock['sample_block'] = function (block, generator) {
  return 'my code string';
};
```

### Statement blocks

Statement blocks represent code that does not return a value.

A statement block's generator simply returns a string.

For example, this code defines a block generator that always returns the same function call.

```js
sampleGenerator.forBlock['left_turn_block'] = function (block, generator) {
  return 'turnLeft()';
};
```

### Value blocks

Value blocks represent code that returns a value.

A value block's generator returns an array containing a string and a [precedence value](/guides/create-custom-blocks/code-generation/operator-precedence). The built-in generators have predefined operator precedence values exported as an `Order` enum.

This code defines a block generator that always returns `1 + 1`:

```js
sampleGenerator.forBlock['two_block'] = function (block, generator) {
  return ['1 + 1', Order.ADDITION];
};
```

### Operator precedence

Operator precedence rules determine how the correct order of operations is maintained during parsing. In Blockly's generators, operator precedence determines when to add parentheses.

--> Read more about [operator precedence in JavaScript](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Operator_Precedence).

--> Read more about [operator precedence in Blockly](/guides/create-custom-blocks/code-generation/operator-precedence).

Since JSON does not allow values that are expressions, the code does not need to consider operator precedence for the generator being built in this codelab. The same value can be used everywhere a precedence value is required. Since parentheses never need to be added to the JSON, call this value `ATOMIC`.

In `src/generators/json.js`, declare a new enum called `Order` and add the `ATOMIC` value:

```js
const Order = {
  ATOMIC: 0,
};
```

---

### Packages Docs Docs Codelabs Custom Generator Codelab Overview (`packages/docs/docs/codelabs/custom-generator/codelab-overview.mdx`)

---
pagination_prev: null
description: Overview of the "Build a custom generator" codelab.
---

import Image from '@site/src/components/Image';

# Build a custom generator

## 1. Codelab overview

### What you'll learn

- How to create a custom language generator.
- How to create block generator definitions for existing blocks.
- How to create block generator definitions for new blocks.
- How to use a custom generator in an application.

### What you'll build

You will build a JSON generator that implements the [JSON language spec](https://www.json.org/json-en.html).

<Image
  src="/images/codelabs/custom-generator/json_workspace.png"
  alt="Screenshot of the toolbox and workspace built in this codelab. It contains blocks that implement the JSON spec, like member, object, lists, strings, and numbers."
  className="codelabImage"
/>

The complete code used in this codelab can be viewed in the `blockly` repository under [packages/docs/docs/codelabs/custom-generator](https://github.com/RaspberryPiFoundation/blockly/tree/main/packages/docs/docs/codelabs/custom-generator/complete-code).

### What you'll need

- Familiarity with JSON and the JSON specification.
- Basic understanding of blocks and toolboxes in Blockly.
- NPM installed ([instructions](https://docs.npmjs.com/downloading-and-installing-node-js-and-npm)).
- Comfort using the command line/terminal.

---

### Packages Docs Docs Codelabs Custom Mutator Codelab Overview (`packages/docs/docs/codelabs/custom-mutator/codelab-overview.mdx`)

---
pagination_prev: null
description: Overview of the "Build a custom mutator" codelab.
---

import Image from '@site/src/components/Image';

# Build a custom mutator

## 1. Codelab overview

### What you'll learn 
- What mutators are and when to use them
- How to create a custom mutator
- How to use context menus to create a custom mutator UI
- When and how to fire events during a mutation

### What you'll build
A custom list mutator that uses the context menu to add and remove items.

<Image
  src="/images/codelabs/custom-mutator/finished_block.png"
  alt="Screenshot of the block built in this codelab. There are multiple inputs to the block, with a context menu open that shows options for 'Add Item' and 'Remove Item'"
  className="codelabImage"
/>

### What you'll need
- Basic understanding of Blockly blocks, toolboxes, and workspaces.
- Understanding of context menus in Blockly.
- NPM installed ([instructions](https://docs.npmjs.com/downloading-and-installing-node-js-and-npm)).
- Comfort using the command line/terminal.

---

### Packages Docs Docs Codelabs Custom Renderer Codelab Overview (`packages/docs/docs/codelabs/custom-renderer/codelab-overview.mdx`)

---
pagination_prev: null
description: Overview of the "Build custom renderers" codelab.
---

# Build custom renderers

## 1. Codelab overview

### What you'll learn

- How to define and register a custom renderer.
- How to override renderer constants.
- How to change the shape of connection notches.
- How to set a connection's shape based on its type checks.

### What you'll build

This codelab builds a custom renderer which adjusts renderer constants and uses different connection shapes depending on the input types.



The complete code used in this codelab can be viewed in the `blockly` repository under [packages/docs/docs/codelabs/custom-renderer](https://github.com/RaspberryPiFoundation/blockly/tree/main/packages/docs/docs/codelabs/custom-renderer/complete-code).

### What you'll need

- Basic understanding of renderers and toolboxes in Blockly.
- NPM installed ([instructions](https://docs.npmjs.com/downloading-and-installing-node-js-and-npm)).
- Comfort using the command line/terminal.

---

### Packages Docs Docs Codelabs Custom Toolbox Codelab Overview (`packages/docs/docs/codelabs/custom-toolbox/codelab-overview.mdx`)

---
pagination_prev: null
description: Overview of the "Customizing a Blockly toolbox" codelab.
---

import Image from '@site/src/components/Image';

# Customizing a Blockly toolbox

## 1. Codelab overview

### What you'll learn

This codelab will focus on customizing the Blockly toolbox.

In this codelab you will learn:

1. How to add a background color to a toolbox category.
1. How to change the look of a selected category.
1. How to add a custom CSS classes to a toolbox category.
1. How to change the structure of your category HTML.
1. How to add a custom toolbox item.

### What you'll build

Over the course of this codelab you will customize your toolbox categories as well
as create a custom toolbox item.
The resulting toolbox is shown below.

<Image
  src="/images/codelabs/custom-toolbox/final_toolbox.png"
  alt="A toolbox with colored background and the blockly label above the category text."
  className="codelabImage"
/>

The code samples are written in ES6 syntax. You can find the code for the [completed custom toolbox](https://github.com/RaspberryPiFoundation/blockly/tree/main/packages/docs/docs/codelabs/custom-toolbox/complete-code) on GitHub.

### What you'll need

- A browser.
- A text editor.
- Basic knowledge of HTML, CSS, and JavaScript.
- node.js and npm installed ([instructions](https://docs.npmjs.com/downloading-and-installing-node-js-and-npm)).
- Comfort using the command line/terminal.
- Basic understanding of the [Blockly toolbox](/guides/configure/toolboxes/toolbox).

Throughout this codelab we will be talking about toolbox definitions.
It may help to review the related [toolbox definition documentation] before starting this codelab.

---

### Packages Docs Docs Codelabs Getting Started Codelab Overview (`packages/docs/docs/codelabs/getting-started/codelab-overview.mdx`)

---
pagination_prev: null
description: Overview of the "Getting started with Blockly" codelab.
---

import Image from '@site/src/components/Image';

# Getting started with Blockly

## 1. Codelab overview

### What you'll learn

This codelab will teach you how to modify a simple web app to include the [Blockly](/guides/get-started/what-is-blockly) visual programming library.

### What is Blockly?

Blockly is a library for building block programming apps.

Block programming allows users to create scripts and programs by using visual blocks, even if they do not know any programming language.

Blockly includes everything you need for defining and rendering blocks in a drag-n-drop editor. Each block represents a chunk of code that can be easily stacked and translated into code.

### What you'll build

A version of Blockly's sample app, built from scratch. 

<Image
  src="/images/codelabs/getting-started/full_page_finished.png"
  alt="Blockly workspace with a toolbox, blocks, and a code preview window that shows code generated from blocks in the workspace."
  className="codelabImage"
/>

### What you'll need

- A browser
- A text editor
- npm installed ([instructions](https://docs.npmjs.com/downloading-and-installing-node-js-and-npm)).
- Basic knowledge of HTML, CSS and JavaScript

This codelab is focused on Blockly. The app structure, non-relevant concepts and code are glossed over and are provided for you to simply copy and paste.

---

### Packages Docs Docs Codelabs Theme Extension Identifier Codelab Overview (`packages/docs/docs/codelabs/theme-extension-identifier/codelab-overview.mdx`)

---
pagination_prev: null
description: Overview of the "Customizing your themes" codelab.
---

import Image from '@site/src/components/Image';

# Customizing your themes

## 1. Codelab overview

### What you'll learn

In this codelab you will learn how to:

- Add component styles.
- Add a category style.
- Add a block style.

### What you'll build

You'll start from the Blockly sample app and give it a custom "Halloween" theme,
customizing the colours of the workspace components, the toolbox categories, and
the blocks themselves.

<Image
  src="/images/codelabs/theme-extension/block_styles.png"
  alt="A Blockly workspace with a custom orange and purple Halloween theme."
  className="codelabImage"
/>

The code samples are written in ES6 syntax. You can find the code for the
[completed theme codelab](https://github.com/RaspberryPiFoundation/blockly/tree/main/packages/docs/docs/codelabs/theme-extension-identifier/complete-code)
on GitHub.

### What you'll need

- A browser.
- A text editor.
- Basic knowledge of HTML, CSS, and JavaScript.
- node.js and npm installed ([instructions](https://docs.npmjs.com/downloading-and-installing-node-js-and-npm)).
- Comfort using the command line/terminal.

This codelab is focused on Blockly's theme extension. Non-relevant concepts
are glossed over and provided for you to simply copy and paste.

---

### Packages Docs Docs Codelabs Validation And Warnings Codelab Overview (`packages/docs/docs/codelabs/validation-and-warnings/codelab-overview.mdx`)

---
pagination_prev: null
description: Overview of the "Block validation and warnings" codelab.
---

import Image from '@site/src/components/Image';

# Block validation and warnings

## 1. Codelab overview

### What you'll learn

This codelab will show you how to ensure that custom blocks either:

1. have everything they need to be able to generate valid code, or
1. display a visual warning to the user that the block is currently invalid.

### What you'll build

In this codelab, you'll create a new custom block type that generates a list of numbers counting up within a given range. The block will validate itself and display a warning if the first number in the range is greater than the last number:

<Image
  src="/images/codelabs/validation-and-warnings/final_range_blocks.png"
  alt="Two instances of a custom block, one with a validation warning."
  className="codelabImage"
/>

You can find the code for the [completed custom block](https://github.com/RaspberryPiFoundation/blockly/tree/main/packages/docs/docs/codelabs/validation-and-warnings/complete-code) on GitHub.

### What you'll need

- A browser.
- A text editor.
- Basic knowledge of HTML, CSS, and JavaScript.
- node.js and npm installed ([instructions](https://docs.npmjs.com/downloading-and-installing-node-js-and-npm)).
- Comfort using the command line/terminal.
- Basic understanding of the [Blockly toolbox](/guides/configure/toolboxes/toolbox).
- Basic understanding of [using JSON to define custom blocks](/guides/create-custom-blocks/define/structure-json).

---

### Packages Docs Docs Guides Contribute Index (`packages/docs/docs/guides/contribute/index.mdx`)

---
description: How to contribute (not just code!) to Blockly.
title: Contribute to Blockly
image: images/blockly_banner.png
---

# Contribute to Blockly

Blockly is an open-source project with a strong community, and we welcome your
contributions.

## How you can help

- [File bugs or feature requests](/guides/contribute/get-started/write_a_good_issue)
- [Fix issues](/guides/contribute/get-started/write_a_good_pr)
- [Add tests](/guides/contribute/core/unit_testing)
- [Write codelabs](/guides/contribute/core/write_a_codelab)
- [Write plugins](/guides/contribute/core/plugins/add_a_plugin)
- [Answer questions](https://groups.google.com/g/blockly)

## Where to start

- If you're new to open source development, or you want to get more background
  knowledge, head over to the
  [Getting Started contributing](/guides/contribute/get-started)
  guides.
- If you are ready to jump in, check out the
  [Contributing to Core](/guides/contribute/core) or
  [Contributing to Samples](/guides/contribute/samples) guides.

### Talk to us!

Join our
[forum for developers](https://groups.google.com/g/blockly) and
say hello. Show us your prototypes early; collectively we have a lot of
experience and can offer hints which will save you time. Plus, we always love to
hear about new projects and use cases for Blockly!

---

### Packages Docs Docs Guides Create Custom Blocks Overview (`packages/docs/docs/guides/create-custom-blocks/overview.mdx`)

---
description: Introduction to creating custom blocks.
title: Custom blocks overview
image: images/blockly_banner.png
---

import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';

# Custom blocks overview

Blockly comes with a large number of predefined blocks, from mathematical
functions to looping structures. However, most applications need to define and
implement custom blocks for their domain. For example, a drawing application
might need blocks to draw lines and circles and a robotics application might
need blocks to move an arm and manipulate a claw.

To define and use a new type of block, you need three things:

- **Block definition**: Defines the look and feel of a block type as well as
  certain behaviors.
- **Block-code generator**: Generates the code string for blocks of this type.
  It is always written in JavaScript, even if the target language is not
  JavaScript.
- **Toolbox reference**: A reference to the block type in the toolbox, so
  users can add it to the workspace.

## Block definition

A **block definition** defines the look and feel of a block, such as its text,
fields, connections, and colour. It can also define block-specific behavior,
such as a block-specific event handler. For example, this block:



can be defined in JSON or JavaScript as follows:

<Tabs groupId="group-1">
  <TabItem value="json" label="JSON" default>
  ```js
  Blockly.common.defineBlocksWithJsonArray([{
    "type": "string_length",
    "message0": 'length of %1',
    "args0": [
      {
        "type": "input_value",
        "name": "VALUE",
        "check": "String"
      }
    ],
    "output": "Number",
    "colour": 160,
    "tooltip": "Returns number of letters in the provided text.",
    "helpUrl": "http://www.w3schools.com/jsref/jsref_length_string.asp"
  }]);
  ```
  </TabItem>
  <TabItem value="javascript" label="JavaScript">
  ```js
  Blockly.Blocks['string_length'] = {
     init: function() {
       this.appendValueInput('VALUE')
           .setCheck('String')
           .appendField('length of');
       this.setOutput(true, 'Number');
       this.setColour(160);
       this.setTooltip('Returns number of letters in the provided text.');
       this.setHelpUrl('http://www.w3schools.com/jsref/jsref_length_string.asp');
     }
  };
  ```
  </TabItem>
</Tabs>
For more information about block definitions and how they work, see [What's a
block
definition?](/guides/create-custom-blocks/define/block-definitions).

## Block-code generators

To transform a block into code, you need separate generator functions for each
language you want to generate. For example, here is a generator that generates
JavaScript:

```js
javascriptGenerator.forBlock['string_length'] = function (block, generator) {
  // String or array length.
  var argument0 =
    generator.valueToCode(block, 'VALUE', Order.FUNCTION_CALL) || "''";
  return [argument0 + '.length', Order.MEMBER];
};
```

The generator function accepts the block being processed and a language
generator. It generates code for any blocks attached to inputs (such as the
`VALUE` input in the example) and any fields, and then concatenates the
resulting strings into a larger expression.

For more information, see [Block-code
generators](/guides/create-custom-blocks/code-generation/block-code).

## Toolbox reference

After you have defined your block type, use the type name to reference it in a
toolbox:

<Tabs groupId="group-2">
  <TabItem value="json" label="JSON" default>
  ```js
  var toolbox = {
       "kind": "categoryToolbox",
       "name": "Text"
       "contents": [
         {
           "kind": "block",
           "type": "string_length"
         },
       ]
     };
  ```
  </TabItem>
  <TabItem value="xml" label="XML">
  ```html
  <xml id="toolbox" style="display: none"> WHY IS THERE DISPLAY: NONE HERE?
     <category name="Text">
       <block type="string_length"></block>
     </category>
     ...
  </xml>
  ```
  </TabItem>
</Tabs>
For more information, see [Define a flyout
toolbox](/guides/configure/toolboxes/flyout) or [Define a category
toolbox](/guides/configure/toolboxes/category).

---

### Packages Docs Docs Guides Design App Overview (`packages/docs/docs/guides/design/app-overview.mdx`)

---
description: Discusses how Blockly is used in applications.
title: Introduction to Blockly applications
image: images/blockly_banner.png
---

import Image from '@site/src/components/Image';

# Introduction to Blockly applications

A Blockly application is a web application that contains a Blockly editor
(workspace). This document gives examples of what Blockly applications are used
for and looks at typical UI features.

If you haven't already done so, be sure to read the [visual
glossary](/guides/get-started/workspace-anatomy) and [basic application
steps](/guides/get-started/workspace-creation) before continuing with
this document.

## What do Blockly applications do?

Blockly applications help users write programs in a variety of fields, from
video games to robotics to data analysis. Users **write their programs using
blocks**, which the application uses to **generate text-based code**, such as
JavaScript or Python. The application then **runs the generated code directly**
or the user **downloads and runs it on another platform**, such as a robot or
hand-held video game controller.

Here are some examples of the kinds of programs users write with Blockly
applications:

- **Puzzle solutions, animation, or music:** The generated code solves a
  puzzle (like a maze), displays an animation, or plays music. For an example,
  see [Code.org's Music Lab](https://studio.code.org/projects/music/new).

- **Video games:** The generated code runs a video game. For example, create
  the first two levels of "Whack the Mole" in [MakeCode
  Arcade](https://arcade.makecode.com/) and download the game to a controller
  or play it in the simulator.

- **Robotics:** The generated code directs a robot. For example, program a
  robot with [Ozoblockly](https://games.ozoblockly.com/shapetracer-freeform)
  and download it to a real robot or run it in the simulator.

- **Drawing:** The generated code draws a 2D or 3D drawing. For an example,
  see [BlocksCAD](https://www.blockscad3d.com/editor/).

- **Data analysis:** The generated code analyzes data and creates a graph. For
  an example, see [this demonstration of the Dialogic
  Platform](https://dialogiconderzoek.nl/diadashboard/platform/demo1.gif).

- **Application-specific code:** The generated code performs a task specific
  to a particular application. For example, [Blockly Developer Tools](https://raspberrypifoundation.github.io/blockly-samples/examples/developer-tools/index.html)
  is a tool for designing new Blockly blocks. It generates block definition
  code, which users copy and paste into their own Blockly application.

## User interfaces

A good way to understand the typical components of Blockly applications is to
look at their user interfaces.

### Basic UI components

Almost all Blockly applications share a few basic components: a Blockly editor
(workspace), an output panel, and a "Run" button. For example, here is the UI of
the [Maze](https://blockly.games/maze?level=4) in Blockly Games.

<Image
  alt="The UI of a maze application with an editor, an output panel, and a Run button."
  src="/images/application-overview/games-maze.png"
  srcDark="/images/application-overview/games-maze-dark.png"
  className="blockly"
  width="75%"
/>

A few Blockly applications omit the "Run" button and instead update the output
panel every time the user makes a change. For example, the
[Graph](https://raspberrypifoundation.github.io/blockly-samples/examples/graph-demo/index.html)
application in Blockly's samples has two output panels (one for the graph and
one for the equation) that it updates on every change.

<Image
  alt="The UI of a graph application with an editor, an output panel for an equation constructed by the user, and an output panel for a graph of that equation."
  src="/images/application-overview/graph-sample.png"
  srcDark="/images/application-overview/graph-sample-dark.png"
  width="75%"
/>

Some applications don't have an output panel. This is most common in hardware
applications, such as those for programming robots. While some of these
applications include a hardware simulator, many of them just let users download
and run the generated code directly on the target device.

### Additional UI components

Most applications have additional UI components. Some of these meet general
needs, such as saving the user's work, while others fulfill application-specific
needs, such as designing a GUI. Here are some examples:

- [Scratch](https://scratch.mit.edu/), an application for creating animations
  and video games, has graphics and sound editors; panels to create new
  sprites and backdrops; and file, edit, and settings menus:

  <Image
    alt="The Scratch user interface."
    src="/images/application-overview/mit-scratch.png"
    srcDark="/images/application-overview/mit-scratch-dark.png"
    width="85%"
  />

- [MakeCode Arcade](https://www.microsoft.com/en-us/makecode), an application
  for creating video games, has output controls, code and graphics editors, a
  settings menu, and download and save buttons. Its output panel simulates a
  handheld game controller.

  <Image
    alt="The MakeCode Arcade user interface."
    src="/images/application-overview/makecode-arcade.png"
    srcDark="/images/application-overview/makecode-arcade-dark.png"
    width="85%"
  />

- [MIT App Inventor](https://appinventor.mit.edu/), an application for
  creating phone apps, has separate screens for its GUI designer and Blockly
  editor, as well as file, connection, build, and settings menus. Instead of
  an output panel, users test generated code on their phone.

  <Image
    alt="The GUI designer in the App Inventor user interface"
    src="/images/application-overview/mit-app-inventor-gui.png"
    srcDark="/images/application-overview/mit-app-inventor-gui-dark.png"
    width="85%"
  />
  <Image
    alt="The Blockly editor in the App Inventor user interface"
    src="/images/application-overview/mit-app-inventor-blockly.png"
    srcDark="/images/application-overview/mit-app-inventor-blockly-dark.png"
    width="85%"
  />

Which additional components you should include depends on your application's
goals and the abilities of your users. Some common components are:

- Administration:
  - File management (new, open, save, save as, delete)
  - Account management (create, login, logout)
  - Settings (language, UI configuration)

- Programming:
  - Edit commands (undo, redo, copy, cut, paste, duplicate)
  - GUI designer
  - Graphics and sound editors
  - Code editor or read-only code display

- Testing
  - Output configuration (start/stop, playback speed, volume, screenshot,
    etc.)
  - Debugger (breakpoints, run, step, block highlighting)
  - Set test parameters

- Hardware
  - Connection (USB, Bluetooth, QR code)
  - Configuration (choose model, choose accessories, assign component names)
  - Control (manually control robot, record robot position)
  - Download code

- Help
  - Documentation
  - Interactive tutorials
  - Context-sensitive help

## Where do I go from here?

If you're still thinking about your application, continue reading about [design
considerations](/guides/design/applications).

If you want to see what it's like to build a simple application, try the
[Getting started with Blockly
codelab](/codelabs/getting-started/codelab-overview).

And if you're ready to write your application:

- [Build your editor](/guides/configure/configuration_struct)
- [Build your blocks](/guides/create-custom-blocks/overview)
- [Build your application](/guides/app-integration/run-code)

---

### Packages Docs Docs Guides Get Started Sample App Overview (`packages/docs/docs/guides/get-started/sample-app-overview.mdx`)

# Blockly Sample App

## Purpose

The Blockly sample app illustrates how to use Blockly together with common programming tools like node/npm, webpack, typescript, eslint, and others. You can use it as the starting point for your own application and modify it as much as you'd like. It contains basic infrastructure for running, building, testing, etc. that you can use even if you don't understand how to configure the related tool yet. When your needs outgrow the functionality provided here, you can replace the provided configuration or tool with your own.

## Quick Start

1. [Install](https://docs.npmjs.com/downloading-and-installing-node-js-and-npm) npm if you haven't before.
2. Run [`npx @blockly/create-package app <application-name>`](https://www.npmjs.com/package/@blockly/create-package) to clone this application to your own machine.
3. Run `npm install` to install the required dependencies.
4. Run `npm run start` to run the development server and see the app in action.
5. If you make any changes to the source code, just save your changes and refresh the browser while the server is running to see them.

## Tooling

The application uses many of the same tools that the Blockly team uses to develop Blockly itself. Following is a brief overview, and you can read more about them on our [developer site](/guides/contribute/core/development_tools).

- Structure: The application is built as an npm package. You can use npm to manage the dependencies of the application.
- Modules: ES6 modules to handle imports to/exports from other files.
- Building/bundling: Webpack to build the source code and bundle it into one file for serving.
- Development server: webpack-dev-server to run locally while in development.
- Testing: Mocha to run unit tests.
- Linting: Eslint to lint the code and ensure it conforms with a standard style.
- UI Framework: Does not use a framework. For more complex applications, you may wish to integrate a UI framework like React or Angular.

You can disable, reconfigure, or replace any of these tools at any time, but they are preconfigured to get you started developing your Blockly application quickly.

## Structure

- `package.json` contains basic information about the app. This is where the scripts to run, build, etc. are listed.
- `package-lock.json` is used by npm to manage dependencies
- `webpack.config.js` is the configuration for webpack. This handles bundling the application and running our development server.
- `src/` contains the rest of the source code.
- `dist/` contains the packaged output (that you could host on a server, for example). This is ignored by git and will only appear after you run `npm run build` or `npm run start`.

### Source Code

To get an in-depth overview of the sample app's source code, see the [getting started codelab](/codelabs/getting-started/codelab-overview/) which goes through the process of creating this app.
Here is a briefer overview of the files in the source code:  

- `index.html` contains the skeleton HTML for the page. This file is modified during the build to import the bundled source code output by webpack.
- `index.js` is the entry point of the app. It configures Blockly and sets up the page to show the blocks, the generated code, and the output of running the code in JavaScript.
- `serialization.js` has code to save and load the workspace using the browser's local storage. This is how your workspace is saved even after refreshing or leaving the page. You could replace this with code that saves the user's data to a cloud database instead.
- `toolbox.js` contains the toolbox definition for the app. The current toolbox contains nearly every block that Blockly provides out of the box. You probably want to replace this definition with your own toolbox that uses your custom blocks and only includes the default blocks that are relevant to your application.
- `blocks/text.js` has code for a custom text block, just as an example of creating your own blocks. You probably want to delete this block, and add your own blocks in this directory.
- `generators/javascript.js` contains the JavaScript generator for the custom text block. You'll need to include block generators for any custom blocks you create, in whatever programming language(s) your application will use.

## Serving

To run your app locally, run `npm run start` to run the development server. This mode generates source maps and ingests the source maps created by Blockly, so that you can debug using unminified code.

To deploy your app so that others can use it, run `npm run build` to run a production build. This will bundle your code and minify it to reduce its size. You can then host the contents of the `dist` directory on a web server of your choosing. If you're just getting started, try using [GitHub Pages](https://pages.github.com/).

---

### Packages Docs Docs Guides Programming Plugin Overview (`packages/docs/docs/guides/programming/plugin_overview.mdx`)

---
description: Plugins, their types, and how to use them.
title: Plugins
image: images/blockly_banner.png
---

import Image from '@site/src/components/Image';
import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';

# Plugins

A plugin is a self-contained piece of code that adds functionality to Blockly.
For example, it might add a custom field, define a new theme, or provide a
custom renderer. Plugins are generally packaged and distributed through npm.

:::note
The [`BlocklyOptions`
object](/guides/configure/configuration_struct#the-options-dictionary)
has a `plugins` property for injecting classes that [customize Blockly
behavior](/guides/configure/customization). While these classes may
be implemented as plugins, this is not required and they are otherwise
unrelated.
:::

For a quick introduction to plugins, see our [Plugins Overview talk
(2021)](https://www.youtube.com/watch?v=rg-V0w7UZFc&list=PLSIUOFhnxEiCjoIwJ0jAdwpTZET73CK7d&index=3).

If you want to create your own plugin, see [Add a
plugin](/guides/contribute/core/plugins/add_a_plugin).

## First- and third-party plugins

_First-party plugins_ are supported by the Blockly team and published under the
`@blockly` scope on npm. They are designed to be usable in a wide range of
Blockly applications.

_Third-party plugins_ are maintained and published independently. They may be
more complex, more experimental, or targeted to a narrower range of Blockly
applications.

## Find a plugin

*   Visit [Blockly Plugins &
    Demos](https://raspberrypifoundation.github.io/blockly-samples/#plugins), which has live
    demos of first-party plugins.

*   Search npm for
    [`keyword:blockly-plugin`](https://www.npmjs.com/search?q=keyword%3Ablockly-plugin).
    Plugins with the scope `@blockly` are published by the Blockly team. For
    broader results, search for
    [`keyword:blockly`](https://www.npmjs.com/search?q=keyword%3Ablockly) or
    [`blockly`](https://www.npmjs.com/search?q=blockly).

*   See the [`packages/plugins/`](https://github.com/RaspberryPiFoundation/blockly/tree/main/packages/plugins) 
    directory on GitHub, which is the location of first-party plugins. 
    Each plugin has a README that describes its behaviour and intended use.

## Install a plugin

We recommend installing plugins with a package manager like npm or yarn. This
makes it easy to receive updates.

*   **Install a plugin with a package manager**
    <Tabs groupId="group-1">
      <TabItem value="npm" label="npm" default>
      ```shell
      npm install @blockly/field-angle
      ```
      </TabItem>
      <TabItem value="yarn" label="yarn">
      ```shell
      yarn add @blockly/field-angle
      ```
      </TabItem>
    </Tabs>
*   **Install a plugin without a package manager**
    <Tabs groupId="group-2">
      <TabItem value="unpkg" label="unpkg" default>
      ```html
      <script src="https://unpkg.com/@blockly/field-angle"></script>
      ```
      
      You can also clone the GitHub repository that contains the plugin. For
      first-party plugins, this is
      [`blockly`](https://github.com/RaspberryPiFoundation/blockly/tree/main).
      </TabItem>
    </Tabs>

Check the plugin's README to see if there are any additional installation
instructions.

## Use a plugin

Each plugin is different, so see the plugin's README for information on how to
use that plugin. The following example shows how to use the
[`@blockly/field-angle`
plugin](https://www.npmjs.com/package/@blockly/field-angle):

1.  Import code from the plugin. How you do this depends on how you installed
    the plugin.
    <Tabs groupId="group-3">
      <TabItem value="npm-or-yarn" label="npm or yarn" default>
      ```js
      import Blockly from 'blockly';
      import {registerFieldAngle} from '@blockly/field-angle';
      ```
      </TabItem>
      <TabItem value="unpkg" label="unpkg">
      You do not need to use an `import` statement.
      </TabItem>
      <TabItem value="cloned-repository" label="Cloned repository">
      ```js
      import {registerFieldAngle} from 'path/to/plugin';
      ```
      </TabItem>
    </Tabs>
1.  Initialize the plugin as needed. Plugins that provide custom fields often
    require you to register the field:

    ```js
    registerFieldAngle();
    ```

1.  Use the plugin.

    ```js
    Blockly.common.defineBlocksWithJsonArray([
      {
        type: "my_angle_block",
        message0: "%1 degrees",
        args0: [
          {
            // Use @blockly/field-angle.
            type: "field_angle",
            name: "FIELDNAME",
            value: 45,
          },
        ],
        output: null,
        style: 'math_blocks'
      },
    ]);
    ```

    <Image alt="A field for picking an angle from a 360-degree dial." src="/images/field-angle.png" width={150} />

## Plugin versions

Blockly uses [semantic versioning](https://semver.org), which requires breaking 
changes to use a new major version. 

Any new plugin that
monkey patches core will have a major version of 0 to [signify initial
development](https://semver.org/#spec-item-4).

Most plugins include the `blockly` package as a
[`peerDependency`](https://docs.npmjs.com/cli/v11/configuring-npm/package-json#peerdependencies)
rather than a `dependency`. This is because we assume that you have already
installed Blockly. (It doesn't make sense to use a plugin without using
Blockly.) Starting with Blockly v13, first-party plugins share an exact version 
number with core Blockly. This means that in order to use a certain plugin, all
you can simply check your Blockly version and use the same plugin version. 

<details>
<summary>What if I'm using a major version of Blockly that's older than v13? </summary>

Keeping Blockly up-to-date is strongly recommended, so that you get the newest 
features and fixes. However, if you can't upgrade Blockly, you can use the 
following npm command to list all of the pre-v13 versions of a plugin alongside 
the minimum Blockly version that they support:

```
npm view '@blockly/block-plus-minus@<13' peerDependencies.blockly
```

Just replace block-plus-minus with the name of whichever plugin you'd like to 
use.

</details>

When you add a plugin to your application's `package.json`, the default is to
include a caret before the version:

```json
"dependencies": {
  "@blockly/field-angle": "^13.2.1"
}
```

This will let npm install any minor version at or above the listed version, so
version `13.3.1` or `13.2.6` works, but a new major version such as `14.0.1` would
not. When you update to a major version of Blockly, you should update your plugins
as well.

### Keeping plugins up to date with Dependabot

[Dependabot](https://github.com/dependabot) is a popular GitHub tool for 
automated dependency updates. If your project is hosted on GitHub, you can use 
Dependabot to ensure that Blockly and its plugins are updated together.

To start with, your project's `dependabot.yml` file might look something like 
this:

```
updates:
  - package-ecosystem: 'npm' 
    directory: '/' 
    target-branch: 'main'
    schedule:
      interval: 'weekly'
```

In `dependabot.yml`, you can group Blockly and its plugins together using 
Dependabot's [groups option](https://docs.github.com/en/code-security/reference/supply-chain-security/dependabot-options-reference#groups--). 
For example:

```
updates:
  - package-ecosystem: 'npm' 
    directory: '/' 
    target-branch: 'main'
    schedule:
      interval: 'weekly'
    groups:
      blockly: # You can give this group a different name if you'd like
        patterns:
          - 'blockly'
          - '@blockly/*' # You can use the wildcard (*) notation to specify any plugin
```

---

### Packages Docs Docs Codelabs Context Menu Option Complete Code README (`packages/docs/docs/codelabs/context-menu-option/complete-code/README.md`)

# Completed code

The finished code for the [Customizing context menus](../codelab-overview.mdx) codelab.

## Run it

To run the complete code, navigate to the `complete-code` folder in your terminal, then run: 

```bash
npm install   # downloads the libraries the app needs (one time)
npm start     # opens the app at http://localhost:...
```

New to npm? See [installing node & npm](https://docs.npmjs.com/downloading-and-installing-node-js-and-npm).

---

### Packages Docs Docs Codelabs Css Complete Code README (`packages/docs/docs/codelabs/css/complete-code/README.md`)

# Completed code

The finished code for the [Use CSS in Blockly](../codelab-overview.mdx) codelab.

## Run it

To run the complete code, navigate to the `complete-code` folder in your terminal, then run: 

```bash
npm install   # downloads the libraries the app needs (one time)
npm start     # opens the app at http://localhost:...
```

New to npm? See [installing node & npm](https://docs.npmjs.com/downloading-and-installing-node-js-and-npm).

---

### Packages Docs Docs Codelabs Custom Generator Complete Code README (`packages/docs/docs/codelabs/custom-generator/complete-code/README.md`)

# Completed code

The finished code for the [Build a custom generator](../codelab-overview.mdx) codelab.

## Run it

To run the complete code, navigate to the `complete-code` folder in your terminal, then run: 

```bash
npm install   # downloads the libraries the app needs (one time)
npm start     # opens the app at http://localhost:...
```

New to npm? See [installing node & npm](https://docs.npmjs.com/downloading-and-installing-node-js-and-npm).

---

### Packages Docs Docs Codelabs Custom Mutator Complete Code README (`packages/docs/docs/codelabs/custom-mutator/complete-code/README.md`)

# Blockly Sample App

## Purpose

This app illustrates how to use Blockly together with common programming tools like node/npm, webpack, typescript, eslint, and others. You can use it as the starting point for your own application and modify it as much as you'd like. It contains basic infrastructure for running, building, testing, etc. that you can use even if you don't understand how to configure the related tool yet. When your needs outgrow the functionality provided here, you can replace the provided configuration or tool with your own.

## Quick Start

1. [Install](https://docs.npmjs.com/downloading-and-installing-node-js-and-npm) npm if you haven't before.
2. Run [`npx @blockly/create-package app <application-name>`](https://www.npmjs.com/package/@blockly/create-package) to clone this application to your own machine.
3. Run `npm install` to install the required dependencies.
4. Run `npm run start` to run the development server and see the app in action.
5. If you make any changes to the source code, just refresh the browser while the server is running to see them.

## Tooling

The application uses many of the same tools that the Blockly team uses to develop Blockly itself. Following is a brief overview, and you can read more about them on our [developer site](https://docs.blockly.com/guides/contribute/core/development_tools/).

- Structure: The application is built as an npm package. You can use npm to manage the dependencies of the application.
- Modules: ES6 modules to handle imports to/exports from other files.
- Building/bundling: Webpack to build the source code and bundle it into one file for serving.
- Development server: webpack-dev-server to run locally while in development.
- Testing: Mocha to run unit tests.
- Linting: Eslint to lint the code and ensure it conforms with a standard style.
- UI Framework: Does not use a framework. For more complex applications, you may wish to integrate a UI framework like React or Angular.

You can disable, reconfigure, or replace any of these tools at any time, but they are preconfigured to get you started developing your Blockly application quickly.

## Structure

- `package.json` contains basic information about the app. This is where the scripts to run, build, etc. are listed.
- `package-lock.json` is used by npm to manage dependencies
- `webpack.config.js` is the configuration for webpack. This handles bundling the application and running our development server.
- `src/` contains the rest of the source code.
- `dist/` contains the packaged output (that you could host on a server, for example). This is ignored by git and will only appear after you run `npm run build` or `npm run start`.

### Source Code

- `index.html` contains the skeleton HTML for the page. This file is modified during the build to import the bundled source code output by webpack.
- `index.js` is the entry point of the app. It configures Blockly and sets up the page to show the blocks, the generated code, and the output of running the code in JavaScript.
- `serialization.js` has code to save and load the workspace using the browser's local storage. This is how your workspace is saved even after refreshing or leaving the page. You could replace this with code that saves the user's data to a cloud database instead.
- `toolbox.js` contains the toolbox definition for the app. The current toolbox contains nearly every block that Blockly provides out of the box. You probably want to replace this definition with your own toolbox that uses your custom blocks and only includes the default blocks that are relevant to your application.
- `blocks/text.js` has code for a custom text block, just as an example of creating your own blocks. You probably want to delete this block, and add your own blocks in this directory.
- `generators/javascript.js` contains the JavaScript generator for the custom text block. You'll need to include block generators for any custom blocks you create, in whatever programming language(s) your application will use.

## Serving

To run your app locally, run `npm run start` to run the development server. This mode generates source maps and ingests the source maps created by Blockly, so that you can debug using unminified code.

To deploy your app so that others can use it, run `npm run build` to run a production build. This will bundle your code and minify it to reduce its size. You can then host the contents of the `dist` directory on a web server of your choosing. If you're just getting started, try using [GitHub Pages](https://pages.github.com/).

---

### Packages Docs Docs Codelabs Custom Renderer Complete Code README (`packages/docs/docs/codelabs/custom-renderer/complete-code/README.md`)

# Completed code

The finished code for the [Build a custom renderer](../codelab-overview.mdx) codelab.

## Run it

To run the complete code, navigate to the `complete-code` folder in your terminal, then run: 

```bash
npm install   # downloads the libraries the app needs (one time)
npm start     # opens the app at http://localhost:...
```

New to npm? See [installing node & npm](https://docs.npmjs.com/downloading-and-installing-node-js-and-npm).

---

### Packages Docs Docs Codelabs Custom Toolbox Complete Code README (`packages/docs/docs/codelabs/custom-toolbox/complete-code/README.md`)

# Completed code

The finished code for the [Customizing a Blockly toolbox](../codelab-overview.mdx) codelab.

## Run it

To run the complete code, navigate to the `complete-code` folder in your terminal, then run: 

```bash
npm install   # downloads the libraries the app needs (one time)
npm start     # opens the app at http://localhost:...
```

New to npm? See [installing node & npm](https://docs.npmjs.com/downloading-and-installing-node-js-and-npm).

---

### Packages Docs Docs Codelabs Getting Started Complete Code README (`packages/docs/docs/codelabs/getting-started/complete-code/README.md`)

# Completed code

The finished code for the [Getting started](../codelab-overview.mdx) codelab.

## Run it

To run the complete code, navigate to the `complete-code` folder in your terminal, then run: 

```bash
npm install   # downloads the libraries the app needs (one time)
npm start     # opens the app at http://localhost:...
```

New to npm? See [installing node & npm](https://docs.npmjs.com/downloading-and-installing-node-js-and-npm).

---

### Packages Docs Docs Codelabs Theme Extension Identifier Complete Code README (`packages/docs/docs/codelabs/theme-extension-identifier/complete-code/README.md`)

# Completed code

The finished code for the [Customizing your themes](../codelab-overview.mdx) codelab.

## Run it

To run the complete code, navigate to the `complete-code` folder in your terminal, then run: 

```bash
npm install   # downloads the libraries the app needs (one time)
npm start     # opens the app at http://localhost:...
```

New to npm? See [installing node & npm](https://docs.npmjs.com/downloading-and-installing-node-js-and-npm).

---

### Packages Docs Docs Codelabs Validation And Warnings Complete Code README (`packages/docs/docs/codelabs/validation-and-warnings/complete-code/README.md`)

# Completed code

The finished code for the [block validation and warnings](../codelab-overview.mdx) codelab.

## Run it

To run the complete code, navigate to the `complete-code` folder in your terminal, then run: 

```bash
npm install   # downloads the libraries the app needs (one time)
npm start     # opens the app at http://localhost:...
```

New to npm? See [installing node & npm](https://docs.npmjs.com/downloading-and-installing-node-js-and-npm).

---

### Packages Docs Docs Guides Contribute Core Index (`packages/docs/docs/guides/contribute/core/index.mdx`)

---
description: Learn how to contribute changes to Blockly Core.
title: Contribute to core
image: images/blockly_banner.png
---

# Contribute to core

The [Blockly](https://github.com/RaspberryPiFoundation/blockly) core repository contains the
code that is needed to run any Blockly-based application. It also contains the documentation, including codelabs.

## Need to Know

Here is a quick overview of facts about Blockly core you need to know in order
to create a PR.

- The working branch is **main** and all PRs should be made against
  main.
- You must fill out the pull request template with the requested information.
- Code must conform to Blockly's [style guide](style_guide)
- Use [conventional commits](/guides/contribute/get-started/commits)
  in your commit messages and pull request titles.
- PR summaries and comments should be human written, and AI usage is not allowed 
  on issues labeled `good first issue`. Consult the [AI policy](/guides/contribute/core/ai_policy)
  for more information.
- User-visible strings must be in the `/msg/messages.js` file so they may be
  translated. Less than 6% of the world speaks English natively.
- Text on blocks should generally be all lowercase (just like the keywords in
  most programming languages).
- Maintain backwards compatibility. There are a _lot_ of Blockly apps out
  there, don't break everyone else.
- Any new code files must be prefixed with the Apache License v2.0:

  ```js
  /**
   *   @license
   *   Copyright <Current YYYY> Raspberry Pi Foundation
   *   SPDX-License-Identifier: Apache-2.0
   */
  ```

## Make and Verify a Change

1.  Run `npm install` to install dependencies.
1.  Run `npm run start` to start up a server running the playground. You can use
    this page to test the existing behavior. See the
    [playground](/guides/contribute/get-started/playground) page for
    more information.
1.  Make any necessary changes to the code.
1.  If you've left the server running, refresh to see your changes. Otherwise,
    restart the server and verify the code behaves as expected and there are no
    errors or warnings in the console.
1.  Run `npm run build` and ensure there are no build errors.
1.  Write automated tests. Usually, these will be mocha tests in the
    `tests/mocha` directory, but we may ask you for other types of tests.
1.  Run `npm run format` to format the code and automatically fix some lint
    problems.
1.  Run `npm test` to run the automated tests. This also runs `eslint`.
1.  If there are lint errors, run `npm run lint-fix` to fix the problems that
    are autofixable. Address any remaining lint warnings or errors.
1.  If all tests pass, you are ready to open a PR against **main** with your
    changes.

---

### Packages Docs Docs Guides Contribute Get Started Index (`packages/docs/docs/guides/contribute/get-started/index.mdx`)

---
description: Learn about contributing to Blockly.
title: Get started contributing to Blockly
image: images/blockly_banner.png
---

# Get started contributing to Blockly

Blockly is open source and is primarily maintained by a small team. We welcome
contributions from developers outside the core team; there is no way for us to
build every requested feature or fix every reported bug without our community.

:::info
This section contains general guides on contributing to Blockly. These guides 
are generally intended for those who are new to Blockly or new to open-source 
development. 
:::

For information specific to Blockly that you should read before making a
contribution, see the
[Contributing to Core](/guides/contribute/core) and
[Contributing to Samples](/guides/contribute/samples) sections.

## Which repository?

A **repository** contains all the files for a single project. Blockly has two
repositories: blockly and blockly-samples.

**[Blockly](https://github.com/RaspberryPiFoundation/blockly)** is the 
repository for the Blockly library. Use this repository if you want to make a 
change to core Blockly behaviour in a way that will apply to all users of the 
library. Blockly core also contains the documentation, including the codelabs 
and codelab solutions.

**[Blockly samples](https://github.com/raspberrypifoundation/blockly-samples)** 
is the repository for examples that show uses of the Blockly library. Use this 
repository if you want to create or modify a sample.

### Pre work: Understand Git and GitHub basics

We use Git and GitHub for managing version control, collaboration, and distribution
of Blockly. If you're new to Git and GitHub, work through GitHub's
[quickstart](https://docs.github.com/en/free-pro-team@latest/github/getting-started-with-github/quickstart)
tutorials to get comfortable with the basics.

To learn about the rest of Blockly's development tools, see the [Contribute to Core](/guides/contribute/core/) 
documentation.  

### Setup

These are the one-time setup steps you'll need to get started: 

1.  **Install** [Git](https://github.com/git-guides/install-git) and [Node](https://docs.npmjs.com/downloading-and-installing-node-js-and-npm)
1.  **Fork and clone the repository.** GitHub has a wonderful tutorial about
    [forking a repo](https://help.github.com/en/github/getting-started-with-github/fork-a-repo#fork-an-example-repository).
    To apply it to blockly, just replace every instance of
    **octocat/Spoon-Knife** with **RaspberryPiFoundation/blockly** or
    **RaspberryPiFoundation/blockly-samples**, depending on which repository you want to work
    in.

### Step by step

These are the general steps you will follow any time you make a change.

1.  **Sync your fork.** GitHub provides a tutorial for
    [syncing a fork](https://help.github.com/en/github/collaborating-with-issues-and-pull-requests/syncing-a-fork).
1.  **Check out the `main` branch** by running `git checkout main` in a 
    terminal.
1.  **Install** dependencies and build tools by running `npm install` in the
    root directory.
1.  **Create a new branch** by running `git checkout -b myBranchName` in a
    terminal. The branch name should help you remember what you're working on.
1.  **Make your changes.**
1.  **Validate your changes,** following the guide for
    [core](/guides/contribute/core) or
    [samples](/guides/contribute/samples).
1.  **Add your changes** to a commit with `git add your/file/path`.
1.  **Save your changes** with `git commit -m "fix: My commit message"`.
    [Read more about commit messages](commits).
1.  **Push your changes** to GitHub with `git push origin myBranchName`.
1.  **Open a pull request** when your code is ready. A member of the Blockly
    team will review your changes and merge them into Blockly if they are
    approved. For more information see
    [PR Review Process](/guides/contribute/get-started/write_a_good_pr#read-the-review).

---

### Packages Docs Docs Guides Create Custom Blocks Code Generation Overview (`packages/docs/docs/guides/create-custom-blocks/code-generation/overview.mdx`)

---
description: What code generation is, and how to implement it.
title: Code generation
image: images/blockly_banner.png
---

# Code generation

Code generation is the process of turning the blocks on a workspace into a
string of code that can be executed.

Code generation is extremely important, because it is what allows your blocks to
actually _do_ things, like evaluate arithmetic expressions, move a character
through a maze, or configure an online shop!

You can't "run" blocks directly. Instead you generate code strings, and then
execute those.

## Language code generators

To generate code, you have to pick what text-based language you want to
generate. This is because each language has its own code generator.

A **language code generator** (commonly called a **code generator**) is a class
that handles the rules for generating code that are specific to a given
language, but not specific to an individual block. For example, it handles
things like formatting comments, indenting statements, and quoting strings.

Blockly provides 5 built-in code generators:

- JavaScript ES5
- Python 3
- Lua 5.1
- Dart 2
- PHP 7

If this list doesn't include the language you want to generate code for, you can
create a custom language code generator. For a simple example, see the [Build a
custom generator][custom-code-generator] codelab, which creates a JSON language
code generator. For a more complex example, see the [JavaScript code
generator][js-code-generator]. Note that you also need to write block-code
generators for any built-in blocks that you want to use.

## Block-code generators

Each block is responsible for generating its own code. When you create a block,
you need to write a separate block-code generator for each language you want to
support.

A **block-code generator** is a function that returns the code for that block as
a string. For example, a block that compares two numbers returns a string of the
form `'a < b'` and a block that represents an if statement returns a string of
the form `'if (...) {\n...\n};\n'`.

```js
import { javascriptGenerator } from 'blockly/javascript';
import { pythonGenerator } from 'blockly/python';

// Write block-code generators for JavaScript and Python.
javascriptGenerator.forBlock['my_custom_block'] = function (block, generator) {
  /* ... */
};
pythonGenerator.forBlock['my_custom_block'] = function (block, generator) {
  /* ... */
};
```

Block-code generators are called by language code generators.

For more information, see [Block-code
generators](/guides/create-custom-blocks/code-generation/block-code).

## Generate and run code

Your application can generate code at any time. For example, it might generate
code when the end-user clicks a button or every time the user makes a change.

After you've generated the code, you need to figure out how to execute it.
Deciding how to execute it is very application-specific, and outside the scope
of Blockly.

For more information, see [Generate and run
code](/guides/app-integration/run-code).

[custom-code-generator]: /codelabs/custom-generator/codelab-overview
[js-code-generator]: https://github.com/RaspberryPiFoundation/blockly/blob/main/packages/blockly/generators/javascript/javascript_generator.ts

---

### Packages Docs Docs Guides Create Custom Blocks Fields Overview (`packages/docs/docs/guides/create-custom-blocks/fields/overview.mdx`)

---
description: What field are, which kinds are provided by default, and how to customize them.
title: Fields
image: images/blockly_banner.png
---

# Fields

Fields are used to define most UI elements on a block. Examples of fields
include string labels, images, inputs for literal data such as strings and
numbers, and rich editors like date pickers and angle pickers. The simplest
example of a field is the `math_number` block, which uses a `field_number` to
let the user type a number.



:::note
If you need to show meta-information about a block, you probably want an
icon instead. Read more about [Fields vs Icons][fields-vs-icons].
:::

Blockly provides several fields by default to handle a variety of user input.
These can be customized through field-specific configuration or with validators,
which tell a field how to handle specific content in a standard editor.

→ More info on [Built-in fields](/guides/create-custom-blocks/fields/built-in-fields/overview).

→ More info on [Validators](/guides/create-custom-blocks/fields/validators).

If you need a fully custom field it takes a bit more work and you'll want to
read most of the fields documentation. Start by learning about the parts
that make up a field or the overview of creating custom fields.

→ More info on the [anatomy of a field](/guides/create-custom-blocks/fields/anatomy-of-a-field).

→ More info on [creating custom fields](/guides/create-custom-blocks/fields/customizing-fields/overview).

[fields-vs-icons]: /guides/create-custom-blocks/fields/fields-vs-icons

---

### Packages Docs Docs Guides Create Custom Blocks Icons Overview (`packages/docs/docs/guides/create-custom-blocks/icons/overview.mdx`)

---
description: What icons are, and how to customize them.
title: Icons
image: images/blockly_banner.png
---

# Icons

Icons are used to define certain UI elements that show or define "meta"
information about a block. Usually this means they act as a clickable button
that opens a pop up with more information or an editor.

→ More info on [Fields vs Icons][fields-vs-icons].

Blockly provides some built-in icons that fulfill common use cases, like adding
comments or warnings to blocks. You can check out the [reference
documentation][icons-reference] for more information about those.

Blockly also lets you define your own custom icons if the built-in ones don't
serve your use case. For example, you might want an icon that displays version
or copyright information in a pop-up bubble.

→ More info on [Creating custom icons][custom-icons].

[fields-vs-icons]: /guides/create-custom-blocks/fields/fields-vs-icons
[custom-icons]: /guides/create-custom-blocks/icons/creating-custom-icons/basic-implementation
[icons-reference]: /reference/namespaces/icons

---

### Packages Docs Docs Guides Create Custom Blocks Procedures Overview (`packages/docs/docs/guides/create-custom-blocks/procedures/overview.mdx`)

---
description: Overview of how Blockly conceptualizes procedures.
title: Procedures
image: images/blockly_banner.png
---

# Procedures

In computer science terms, a procedure is a reusable bit of code that performs a
specific task.

Blockly implements procedures as a set of blocks that generate code for defining
a procedure, and calling it.



→ More info on [using the blocks](/guides/create-custom-blocks/procedures/using-procedures).

→ More info on [creating custom procedure blocks](/guides/create-custom-blocks/procedures/creating-custom-procedure-blocks).

→ More info on [creating custom procedure models](/guides/create-custom-blocks/procedures/creating-custom-procedure-data-models), which allow you to add new functionality like typed parameters.

## Built-in vs plugin

Blockly provides two implementations of procedure blocks.

One exists in the plugin [@blockly/block-shareable-procedures][shareable-procedures],
which implements procedure blocks that rely on a backing data model. This allows
you to do things with your procedure blocks such as having the definition
block exist in one workspace, and the call block exist in another. The plugin is
the recommended implementation of procedure blocks.

The other is the legacy implementation, provided in Blockly core. These blocks
don't have a backing data model, and all information about procedures comes
from the blocks themselves. The only way a workspace knows which procedures
are available is by inspecting the procedure definition blocks contained in
that workspace. These blocks continue to be supported for backwards
compatibility, but most developers should be able to use the new blocks
provided by the plugin.

- If you are using XML serialization, you can use the new blocks, but they
  won't be shareable across workspaces. That feature requires extra serialization
  that is only provided by the JSON serializer. When using XML, the new blocks
  will behave identically to the legacy blocks.
  [Learn more about upgrading to JSON](https://docs.google.com/document/d/1wv5ORrO4icVHeU15FLSn37mdNLyJpQbMTo7mmTqsGl0/edit?usp=sharing).

- If you have defined custom procedure blocks, they need to be
  [updated](/guides/create-custom-blocks/procedures/creating-custom-procedure-blocks)
  to work with the new data models.

- If you have defined custom procedure definition blocks, _but are using the
  built-in procedure call block_, you need to continue using the legacy caller
  block until you [update](/guides/create-custom-blocks/procedures/creating-custom-procedure-blocks)
  your definition block.

[shareable-procedures]: https://www.npmjs.com/package/@blockly/block-shareable-procedures

---

### Packages Docs Docs Guides Create Custom Blocks Renderers Overview (`packages/docs/docs/guides/create-custom-blocks/renderers/overview.mdx`)

---
description: What a renderer is, built-in renderers, and how to create a custom one.
title: Renderers
image: images/blockly_banner.png
---

# Renderers

The shape of a block is determined by a renderer, based on the
[block's definition][block-definition] (that is, its fields and connections).

## Built-in renderers

Blockly provides three built-in renderers, each of which give a slightly
different feel to the program.

| Renderer | Description                                                                                                         | Image               |
| -------- | ------------------------------------------------------------------------------------------------------------------- | ------------------- |
| Thrasos  | The recommended renderer. It is a more modern take on the geras renderer, with more even spacing and solid borders. | ![thrasos][thrasos] |
| Geras    | The default renderer. It is the original renderer that Blockly was built with.                                      | ![geras][geras]     |
| Zelos    | A renderer based on Scratch-3.0 block design.                                                                       | ![zelos][zelos]     |

To use one of these renderers, pass the name into the configuration options:

```js
Blockly.inject('blocklyDiv', {
  renderer: 'thrasos',
});
```

## Custom renderers

If you want to give your program a different look and feel than any of the
built-in renderers, you can also create a custom renderer. To get started the
Blockly team recommends you:

1. Read through the [renderer concept docs][concept] to learn
   how all of the components of a renderer fit together.
2. Complete the [custom renderer codelab][custom-renderer-codelab] to
   get hands-on practice with custom rendering.
3. Add the [debug renderer][debug-renderer] to your project.
4. Customize your renderer.

[block-definition]: /guides/create-custom-blocks/define/block-definitions
[concept]: /guides/create-custom-blocks/renderers/concepts/overview
[custom-renderer-codelab]: /codelabs/custom-renderer/codelab-overview
[debug-renderer]: https://www.npmjs.com/package/@blockly/dev-tools#debug-renderer
[thrasos]: /images/rendering/renderers/thrasos.png
[geras]: /images/rendering/renderers/geras.png
[zelos]: /images/rendering/renderers/zelos.png

---

### Packages Docs Docs Guides Create Custom Blocks Fields Built In Fields Overview (`packages/docs/docs/guides/create-custom-blocks/fields/built-in-fields/overview.mdx`)

---
title: Built-in fields
image: images/blockly_banner.png
---

# Built-in fields

Blockly provides a number of prebuilt fields that you can use when defining a
block. There are also a number of fields available as
[plugins](/guides/programming/plugin_overview).

Built-in fields:

- [Checkbox](/guides/create-custom-blocks/fields/built-in-fields/checkbox)
- [Dropdown](/guides/create-custom-blocks/fields/built-in-fields/dropdown)
- [Image](/guides/create-custom-blocks/fields/built-in-fields/image)
- [Label](/guides/create-custom-blocks/fields/built-in-fields/label)
- [Serializable label](/guides/create-custom-blocks/fields/built-in-fields/label-serializable)
- [Number](/guides/create-custom-blocks/fields/built-in-fields/number)
- [Text input](/guides/create-custom-blocks/fields/built-in-fields/text-input)
- [Variables](/guides/create-custom-blocks/fields/built-in-fields/variable)

Plugin fields:

- [Angle picker](https://www.npmjs.com/package/@blockly/field-angle)
- [Bitmap](https://www.npmjs.com/package/@blockly/field-bitmap)
- [Colour picker](https://www.npmjs.com/package/@blockly/field-colour)
- [Colour picker with HSV sliders](https://www.npmjs.com/package/@blockly/field-colour-hsv-sliders)
- [Date](https://www.npmjs.com/package/@blockly/field-date)
- [Dropdown grid](https://www.npmjs.com/package/@blockly/field-grid-dropdown)
- [Dependent dropdown](https://www.npmjs.com/package/@blockly/field-dependent-dropdown)
- [Multiline text input](https://www.npmjs.com/package/@blockly/field-multilineinput)
- [Number slider](https://www.npmjs.com/package/@blockly/field-slider)

For a full list of plugin fields, see [Blockly Plugins & Demos][blockly-demos].

[blockly-demos]: https://raspberrypifoundation.github.io/blockly-samples/#fields

---

### Packages Docs Docs Guides Create Custom Blocks Fields Customizing Fields Overview (`packages/docs/docs/guides/create-custom-blocks/fields/customizing-fields/overview.mdx`)

---
description: Methods for customizing fields.
title: Custom fields
image: images/blockly_banner.png
---

# Custom fields

While Blockly provides many useful fields, your application may have a
specialized case. Here are a few steps to take when customizing fields:

1. Read the documentation of any fields similar to what you require; they may
   provide a useful interface for customization. For example,
   [dropdowns](/guides/create-custom-blocks/fields/built-in-fields/dropdown) have a lot of hidden functionality.

2. Consider using a [validator](/guides/create-custom-blocks/fields/validators) to solve your problem.
   Validators allow you to only accept certain values, modify input, or trigger
   functionality when a field's value changes.

3. Consider [extending a field](/guides/create-custom-blocks/fields/customizing-fields/extending).
   If there is a field that represents the value type you require, but you want to
   modify its [editor](/guides/create-custom-blocks/fields/anatomy-of-a-field#editor-display), its
   [appearance](/guides/create-custom-blocks/fields/anatomy-of-a-field#on-block-display), or the
   [text](/guides/create-custom-blocks/fields/customizing-fields/creating#text) it
   displays, you can [create a subclass](/guides/create-custom-blocks/fields/customizing-fields/extending#subclassing)
   that inherits the bulk of the functionality, while overriding the specific parts
   you want to change.

4. [Create a new field type](/guides/create-custom-blocks/fields/customizing-fields/creating).
   While this is the most powerful option, it is also the most time consuming, and
   should generally only be used if you need to store a new value type.

---

### Packages Docs Docs Guides Create Custom Blocks Renderers Concepts Overview (`packages/docs/docs/guides/create-custom-blocks/renderers/concepts/overview.mdx`)

---
description: An overview of important renderer concepts.
title: Renderer concepts
image: images/blockly_banner.png
---

import Image from '@site/src/components/Image';

# Renderer concepts

Before you start building a custom renderer, it is helpful to understand the
different components that make up a renderer, as well as how a block gets
broken up into rows and elements.

## Renderer components

A renderer is built up of several different components. Each component has a
unique job to maximize code reuse and extensibility.

### Renderer

The [renderer][renderer] is a factory class that bundles all of the other
components together.

### Constant provider

The [constant provider][constants] is a collection of numbers, and shapes used
by all of the other components, as well as built-in fields.

### Render info

The [render info][render-info] decides how it a block should be laid out based
on its definition, and then creates a collection of
[measurables](#block-measurables) and data about the block which the
[drawer][drawer] uses to create SVG paths.

### Path Object

The [path object][path-object] contains the SVG elements that live in the dom
and make up the block.

### Drawer

The [drawer][drawer] (as in "one-who-draws") builds SVG [paths][paths] based on
the [render info][render-info] and applies them to the
[path object][path-object].

## Block measurables

A measurable is a rectangle representing a region of a block. Measurables are
what the [render info][render-info] uses to define the layout of the block.

Some measurables also include extra data (such as the visual thing they are
representing), or helper methods that the render info can use to figure out how
to lay out the block.

Different renderers may create custom measurables to change these data or
helper methods.

### Rows

A [row][row] is a horizontal collection of [elements][element] and
[element spacers][element-spacer].

<Image
  alt="A repeat-for block with the rows outlined."
  src="/images/rendering/debug-renderer/row.png"
  width={200}
/>

### Row spacers

A [row spacer][row-spacer] is an empty vertical space that goes between two
rows.

<Image
  alt="A repeat-for block with the row spacers highlighted in blue"
  src="/images/rendering/debug-renderer/row-spacer.png"
  width={200}
/>

### Elements

An [element][element] represents a visual thing on a block. These include
[fields][field], [icons][icon], connections, etc.

<Image
  alt="A repeat-for block with the elements outlined"
  src="/images/rendering/debug-renderer/element.png"
  width={200}
/>

### Element spacers

An [element spacer][element-spacer] is an empty space that goes between elements
in a row.

<Image
  alt="A repeat-for block with the element spacers highlighted in pink"
  src="/images/rendering/debug-renderer/element-spacer.png"
  width={200}
/>

[renderer]: /guides/create-custom-blocks/renderers/concepts/renderer
[constants]: /guides/create-custom-blocks/renderers/concepts/constants
[render-info]: /guides/create-custom-blocks/renderers/concepts/info
[path-object]: /guides/create-custom-blocks/renderers/concepts/path-object
[drawer]: /guides/create-custom-blocks/renderers/concepts/drawer
[paths]: https://developer.mozilla.org/en-US/docs/Web/SVG/Tutorial/Paths
[row]: /guides/create-custom-blocks/renderers/concepts/rows
[element]: /guides/create-custom-blocks/renderers/concepts/elements
[row-spacer]: /guides/create-custom-blocks/renderers/concepts/rows#row-spacer
[element-spacer]: /guides/create-custom-blocks/renderers/concepts/elements#element-spacer
[field]: /guides/create-custom-blocks/fields/overview
[icon]: /guides/create-custom-blocks/icons/overview
[row-image]: /images/rendering/debug-renderer/row.png
[row-spacer-image]: /images/rendering/debug-renderer/row-spacer.png
[element-image]: /images/rendering/debug-renderer/element.png
[element-spacer-image]: /images/rendering/debug-renderer/element-spacer.png

---

### Packages Docs AGENTS (`packages/docs/AGENTS.md`)

# packages/docs — developer documentation site

A Docusaurus site. Built as the `blockly-docs` Nx project; it is not released to npm.

Repo-wide conventions are in the [root `AGENTS.md`](../../AGENTS.md).

## Commands

Run from `packages/docs/`, or from the repo root as `npm run build-docs`.

```bash
npm start          # build the API reference, then serve the site locally
npm run build      # production build
npm run serve      # serve an already-built site
npm run clear      # clear the Docusaurus cache
npm run lint       # ESLint over docs/**/*.mdx
npm run lint-fix
```

## Things to know

- **`docs/reference/` is generated** by TypeDoc during the Docusaurus build, and is
  gitignored. Never edit those files directly — fix the TSDoc in `packages/blockly/core/`
  instead.
- **The reference is built from `blockly_api.json`, not from the current source.** That
  file is a snapshot of the core library's API committed during a release, so the site
  documents the released API rather than whatever is on `main`. To preview your own TSDoc
  changes, run `npm run reference:refresh` to regenerate it locally — then leave it out of
  your commit, since only a release should update it.
- **Markdown and MDX here are linted, not Prettier-formatted.** `packages/docs/**/*.md`
  and `*.mdx` are listed in `.prettierignore` and handled by ESLint with
  `eslint-plugin-mdx` instead, so `npm run format` will not touch them.
- Prose wrapping is preserved rather than reflowed, so existing line breaks in prose are
  intentional — don't rewrap paragraphs you aren't otherwise changing.

---

### Packages Docs Static Robots (`packages/docs/static/robots.txt`)

# Algolia-Crawler-Verif: 836ECEE0BC07004B

# Allow the Algolia Crawler to access the entire site
User-agent: Algolia Crawler
Allow: /

User-agent: *
Allow: /

---

### Packages Docs Docs Codelabs Context Menu Option Add A Context Menu Item (`packages/docs/docs/codelabs/context-menu-option/add-a-context-menu-item.mdx`)

---
description: How to add a context menu item to the registry.
---

import Image from '@site/src/components/Image';

# Customizing context menus

## 3. Add a context menu item

In this section you will create a very basic `Blockly.ContextMenuRegistry.RegistryItem`, then register it to display when you open a context menu on the workspace, a block, or a comment.

### The RegistryItem

A context menu consists of one or more menu options that a user can select. Blockly stores information about menu option as items in a registry. You can think of the _registry items_ as templates for constructing _menu options_. When the user opens a context menu, Blockly retrieves all of the registry items that apply to the current context and uses them to construct a list of menu options.

Each item in the registry has several properties:

- `displayText`: The text to show in the menu. Either a string, or HTML, or a function that returns either of the former.
- `preconditionFn`: Function that returns one of `'enabled'`, `'disabled'`, or `'hidden'` to determine whether and how the menu option should be rendered.
- `callback`: A function called when the menu option is selected.
- `id`: A unique string id for the item.
- `weight`: A number that determines the sort order of the option. Options with higher weights appear later in the context menu.

We will discuss these in detail in later sections of the codelab.

### Make a RegistryItem

Add a function to `src/index.js` named `registerHelloWorldItem`. Create a new registry item in your function:

```js
function registerHelloWorldItem() {
  const helloWorldItem = {
    displayText: 'Hello World',
    preconditionFn: function (scope) {
      return 'enabled';
    },
    callback: function (scope) {},
    id: 'hello_world',
    weight: 100,
  };
}
```

Call your function in `src/index.js`, before the UI element setup and `Blockly.inject` call:

```js
registerHelloWorldItem();

// Set up UI elements and inject Blockly
const codeDiv = document.getElementById('generatedCode').firstChild;
// ...
const ws = Blockly.inject(blocklyDiv, {toolbox});
```

### Register it

Next, register your item with Blockly:

```js
function registerHelloWorldItem() {
  const helloWorldItem = {
    // ...
  };
  Blockly.ContextMenuRegistry.registry.register(helloWorldItem);
}
```

:::note
You will never need to make a new `ContextMenuRegistry`. Always use the singleton `Blockly.ContextMenuRegistry.registry`.
:::

### Enable comment context menus

This codelab demonstrates context menus on workspaces, blocks, and comments. Blockly registers the workspace and block options by default, but the comment options (including the **Add Comment** option you'll use to create comments while testing) must be registered separately. Add this call to `src/index.js`, before the `Blockly.inject` call:

```js
Blockly.ContextMenuItems.registerCommentOptions();
```

### Test it

Refresh the running page (or run `npm start`) and open a context menu on the workspace (right-click with a mouse, or press `Ctrl+Enter` (Windows) or `Command+Enter` (Mac) if you are navigating Blockly with the keyboard). You should see a new option labeled "Hello World" at the bottom of the context menu.

<Image
  src="/images/codelabs/context-menu-option/hello_world.png"
  alt='A context menu. The last option says "Hello World".'
  className="codelabImage"
/>

Next, drag a block onto the workspace and open a context menu on the block. You'll see "Hello World" at the bottom of the block's context menu. Finally, open a context menu on the workspace and create a comment, then open a context menu on the comment's header. "Hello World" should be at the bottom of the context menu.

---

### Packages Docs Docs Codelabs Context Menu Option Callback (`packages/docs/docs/codelabs/context-menu-option/callback.mdx`)

---
description: How to add a callback to a context menu item.
---

import Image from '@site/src/components/Image';

# Customizing context menus

## 7. Callback

The callback function determines what happens when you select the context menu option. Like the precondition, it can use the `scope` argument to access the Blockly component on which the context menu was invoked.

It is also passed a `PointerEvent` which is the original event that triggered opening the context menu (not the event that selected the current option). This lets you, for example, figure out where on the workspace the context menu was opened so you can create a new element there.

As an example, update the help item's `callback` to add a block to the workspace when selected:

```js
    callback: function(scope) {
      Blockly.serialization.blocks.append({
        'type': 'text',
        'fields': {
          'TEXT': 'Now there is a block'
        }
      }, scope.focusedNode);
    },
```

### Test it

- Refresh the running page and open a context menu on the workspace.
- Select the **Help** option.
- A text block should appear in the top left of the workspace.

<Image
  src="/images/codelabs/context-menu-option/there_is_a_block.png"
  alt='A text block containing the text "Now there is a block".'
  className="codelabImage"
/>

---

### Packages Docs Docs Codelabs Context Menu Option Display Text (`packages/docs/docs/codelabs/context-menu-option/display-text.mdx`)

---
description: How to set the display text of a context menu item.
---

import Image from '@site/src/components/Image';

# Customizing context menus

## 8. Display text

So far the `displayText` has always been a simple string, but it can also be HTML, or a function that returns either of the former. Using a function can be useful when you want a context-dependent message.

When defined as a function `displayText` accepts a `scope` argument, just like `callback` and `preconditionFn`.

As an example, add this registry item. The display text depends on the block type.

```js
function registerDisplayItem() {
  const displayItem = {
    displayText: function (scope) {
      if (scope.focusedNode.type.startsWith('text')) {
        return 'Text block';
      } else if (scope.focusedNode.type.startsWith('controls')) {
        return 'Controls block';
      } else {
        return 'Some other block';
      }
    },
    preconditionFn: function (scope) {
      return scope.focusedNode instanceof Blockly.BlockSvg
        ? 'enabled'
        : 'hidden';
    },
    callback: function (scope) {},
    id: 'display_text_example',
    weight: 100,
  };
  Blockly.ContextMenuRegistry.registry.register(displayItem);
}
```

As usual, remember to call `registerDisplayItem()` in `src/index.js`, before `Blockly.inject`.

### Test it

- Refresh the running page and open context menus on various blocks.
- The last context menu option's text should vary based on the block type.

<Image
  src="/images/codelabs/context-menu-option/display_text.png"
  alt='A controls-if block with an open context menu which has "Controls block" as the last item.'
  width={300}
  className="codelabImage"
/>

---

### Packages Docs Docs Codelabs Context Menu Option Precondition Blockly State (`packages/docs/docs/codelabs/context-menu-option/precondition-blockly-state.mdx`)

---
description: How to include a context menu item based on Blockly's state.
---

import Image from '@site/src/components/Image';

# Customizing context menus

## 6. Precondition: Blockly state

Disabling your context menu options half of the time is not useful, but you may want to show or hide an option based on what the user is doing. For example, let's show a **Help** option in the context menu if the user doesn't have any blocks on the workspace. Add this code in `src/index.js`:

```js
function registerHelpItem() {
  const helpItem = {
    displayText: 'Help! There are no blocks',
    preconditionFn: function (scope) {
      if (!(scope.focusedNode instanceof Blockly.WorkspaceSvg)) return 'hidden';
      if (!scope.focusedNode.getTopBlocks().length) {
        return 'enabled';
      }
      return 'hidden';
    },
    callback: function (scope) {},
    id: 'help_no_blocks',
    weight: 100,
  };
  Blockly.ContextMenuRegistry.registry.register(helpItem);
}
```

Don't forget to call `registerHelpItem()` in `src/index.js`, before `Blockly.inject`.

### Test it

- Refresh the running page and open a context menu on the workspace. You should see an option labeled "Help! There are no blocks".

<Image
  src="/images/codelabs/context-menu-option/blockly_state_noblocks.png"
  alt='A context menu, where the last item is "Help! There are no blocks".'
  width={300}
  className="codelabImage"
/>

- Add a block to the workspace and open a context menu on the workspace again. The **Help** option should be gone.

<Image
  src="/images/codelabs/context-menu-option/blockly_state_withblocks.png"
  alt='A block on the workspace, and a context menu open beside it without the "Help" message.'
  width={300}
  className="codelabImage"
/>

---

### Packages Docs Docs Codelabs Context Menu Option Precondition External State (`packages/docs/docs/codelabs/context-menu-option/precondition-external-state.mdx`)

---
description: How to include a context menu item based on an external condition.
---

import Image from '@site/src/components/Image';

# Customizing context menus

## 5. Precondition: External state

Use of the `preconditionFn` is not limited to checking the type of the Blockly component that the context menu was invoked on. You can use it to check for conditions entirely outside of Blockly. For instance, let's disable `helloWorldItem` for the second half of every minute:

```js
    preconditionFn: function (scope) {
      if (
        scope.focusedNode instanceof Blockly.WorkspaceSvg ||
        scope.focusedNode instanceof Blockly.BlockSvg
      ) {
        const now = new Date(Date.now());
        if (now.getSeconds() < 30) {
          return 'enabled';
        }
        return 'disabled';
      }
      return 'hidden';
    },
```

### Test it

Refresh the running page, check your watch, and open a context menu on the workspace to confirm the timing. The option will always be in the menu, but will sometimes be greyed out.

<Image
  src="/images/codelabs/context-menu-option/hello_world_grey.png"
  alt='A context menu. The last option says "Hello World" but the text is grey, indicating that it cannot be selected.'
  className="codelabImage"
/>

---

### Packages Docs Docs Codelabs Context Menu Option Precondition Node Type (`packages/docs/docs/codelabs/context-menu-option/precondition-node-type.mdx`)

---
description: How to include a context menu item based on the node type.
---

import Image from '@site/src/components/Image';

# Customizing context menus

## 4 . Precondition: Node type

Each registry item has a `preconditionFn`. It is called by Blockly to decide whether and how to display an option on a context menu. You'll use it to display the "Hello, World" option on workspace and block context menus, but not on comment context menus.

### The scope argument

The `scope` argument is an object that is passed to `preconditionFn`. You'll use the `scope.focusedNode` property to determine which object the context menu was invoked on. Why a focused node? Because Blockly keeps track of where the user is -- that is, what node (component) the user is focused on -- and opens the context menu on that node.

### Return value

The return value of `preconditionFn` is `'enabled'`, `'disabled'`, or `'hidden'`. An **enabled** option is shown with black text and is selectable. A **disabled** option is shown with grey text and is not selectable. A **hidden** option is not included in the context menu at all.

### Write the function

You can now test `scope.focusedNode` to display the "Hello World" option in workspace and block context menus, but not on any others. Change `preconditionFn` to:

```js
  const helloWorldItem = {
    ...
    preconditionFn: function (scope) {
      if (
        scope.focusedNode instanceof Blockly.WorkspaceSvg ||
        scope.focusedNode instanceof Blockly.BlockSvg
      ) {
        return 'enabled';
      }
      return 'hidden';
    },
    ...
  };
```

Notice that the code tests for where context menus are allowed, rather than where they are not allowed. This is because custom code (such as a plugin) can add context menus to any Blockly component that can be focused. Thus, testing for specific types rather than allowing all (or all but certain types) ensures that context menus are not shown on more components than you anticipated.

### Test it

Open a context menu on the workspace, a block, and a comment. You should see a "Hello World" option on the workspace and block context menus, but not on the comment context menu.

<Image
  src="/images/codelabs/context-menu-option/hello_world_block.png"
  alt='An if block with a context menu with five options. The last option says "Hello World".'
  className="codelabImage"
/>

---

### Packages Docs Docs Codelabs Context Menu Option Separators (`packages/docs/docs/codelabs/context-menu-option/separators.mdx`)

---
description: How to add a separator to a context menu.
---

import Image from '@site/src/components/Image';

# Customizing context menus

## 10. Separators

You can use separators to break your context menu into different sections.

Separators differ from other items in two ways: They cannot have `displayText`, `preconditionFn`, or `callback` properties and they can only be scoped with the `scopeType` property. The latter accepts an enum value of `Blockly.ContextMenuRegistry.ScopeType.WORKSPACE`, `Blockly.ContextMenuRegistry.ScopeType.BLOCK`, or `Blockly.ContextMenuRegistry.ScopeType.COMMENT`.

Use the `weight` property to position the separator. You'll use a weight of `99` to position the separator just above the other options you added, all of which have a weight of `100`.

You need to add a separate item for each separator:

```js
function registerSeparators() {
  const workspaceSeparator = {
    id: 'workspace_separator',
    scopeType: Blockly.ContextMenuRegistry.ScopeType.WORKSPACE,
    weight: 99,
    separator: true,
  };
  Blockly.ContextMenuRegistry.registry.register(workspaceSeparator);

  const blockSeparator = {
    id: 'block_separator',
    scopeType: Blockly.ContextMenuRegistry.ScopeType.BLOCK,
    weight: 99,
    separator: true,
  };
  Blockly.ContextMenuRegistry.registry.register(blockSeparator);
}
```

As usual, remember to call `registerSeparators()` in `src/index.js`, before `Blockly.inject`.

### Test it

Open a context menu on the workspace and a block and check that the separator line is there.

<Image
  src="/images/codelabs/context-menu-option/separator.png"
  alt='A context menu with a separator.'
  width={300}
  className="codelabImage"
/>

---

### Packages Docs Docs Codelabs Context Menu Option Setup (`packages/docs/docs/codelabs/context-menu-option/setup.mdx`)

---
description: Setting up the "Customizing context menus" codelab.
---

import Image from '@site/src/components/Image';

# Customizing context menus

## 2. Setup

### Create the application

Use the [`npx @blockly/create-package app`](https://www.npmjs.com/package/@blockly/create-package) command to create a standalone application that contains a sample setup of Blockly, including custom blocks and a display of the generated code and output.

1. Run `npx @blockly/create-package app context-menu-option-codelab` in your terminal. This will create a Blockly application in the folder `context-menu-option-codelab`.
1. Use `cd` to move into the new directory: `cd context-menu-option-codelab`.
1. Run `npm start` to start the server and run the sample application.
1. The sample app will automatically run in the browser window that opens.

The local address in the address bar of your browser starting with `http://localhost:` shows where your app is. If you accidentally close this window or tab, you can re-open this local address to view the app as long as `npm start` is still running.

### Change the storage key

Before setting up the rest of the application, change the storage key used for this codelab application. This will ensure that the workspace is saved in its own storage, separate from the regular sample app, so that it doesn't interfere with other demos.

In `serialization.js`, change the value of `storageKey` to some unique string. `contextMenuWorkspace` will work:

```js
// Use a unique storage key for this codelab
const storageKey = 'contextMenuWorkspace';
```

### Explore the starter code

Take a moment to explore the code you just created in the `context-menu-option-codelab` folder. If you'd like a more in-depth explanation of all of the code in the sample app, check out the [getting started codelab](/codelabs/getting-started/codelab-overview) which goes through creating this sample app from scratch.

For a briefer outline of the code, visit the [sample app overview](/guides/get-started/sample-app-overview/) page for an overview of the included files and tooling.

---

### Packages Docs Docs Codelabs Context Menu Option Summary (`packages/docs/docs/codelabs/context-menu-option/summary.mdx`)

---
pagination_next: null
description: Summary of the "Customizing context menus" codelab.
---

# Customizing context menus

## 11. Summary

In this codelab you have learned how to create and modify context menu options. You have learned about scope, preconditions, callbacks, and display text.

You can find the code for the [completed context menu codelab](https://github.com/RaspberryPiFoundation/blockly/tree/main/packages/docs/docs/codelabs/context-menu-option/complete-code) on GitHub.

### Additional information

- [Context menu documentation](/guides/configure/context-menus)

- You can also define [block context menus](/guides/configure/context-menus#customize-per-block) directly on a block definition, which is equivalent to adding a precondition based on the type of the block.

---

### Packages Docs Docs Codelabs Context Menu Option Weight And Id (`packages/docs/docs/codelabs/context-menu-option/weight-and-id.mdx`)

---
description: How to set the weight and ID of a context menu item.
---

# Customizing context menus

## 9. Weight and id

The last two properties of a registry item are `weight` and `id`.

### Weight

The `weight` property is a number that determines the order of the options in the context menu. A higher number means your option will be lower in the list.

Test this by updating the `weight` property on one of your new registry items and confirming that the corresponding option moves to the top or bottom of the list.

Note that weight does not have to be positive or integer-valued.

### Id

Every registry item has an `id` that can be used to unregister it. You can use this to get rid of registry items that you don't want.

For instance, you can remove the item that deletes all blocks on the workspace:

```js
Blockly.ContextMenuRegistry.registry.unregister('workspaceDelete');
```

### Default items

For a list of the default registry items that Blockly provides, look at [contextmenu_items.ts](https://github.com/RaspberryPiFoundation/blockly/blob/main/packages/blockly/core/contextmenu_items.ts). Each entry contains both the `id` and the `weight`.

---

### Packages Docs Docs Codelabs Css Blocks (`packages/docs/docs/codelabs/css/blocks.mdx`)

---
title: Use CSS in Blockly - Blocks
description: Styling blocks with CSS
---
import Image from '@site/src/components/Image';

# Use CSS in Blockly

## 6. Blocks

In this section, you will create CSS rules to assign the colours used by the [blocks section](/codelabs/theme-extension-identifier/customize-block-styles) of the themes codelab to the logic, loops, text, and lists blocks. This is a bit more complex than setting component or category colours and you'll do it in several steps.

### Block fill and stroke

Your first step is to set the `fill` and `stroke` of the logic blocks.

Note that setting the `fill` and `stroke` is specific to the
[renderer](/guides/create-custom-blocks/renderers/overview)
you are using. (In this codelab, you are using the Thrasos renderer.) An
important consequence of this is that you need different CSS for different
renderers.

#### Identify the block element

Drag an `if do` block onto the workspace and find it with the element inspector:

```
<body>
  <div class="blocklyDiv">
    <div class="injectionDiv">
      <svg class="blocklySvg">
        <g class="blocklyWorkspace">
          <g class="blocklyBlockCanvas">
            <g class="controls_if blocklyBlock logic_blocks">
```

Notice that the block's `<g>` element has classes for the block's type (`controls_if`) and style (`logic_blocks`). These are the values of the [`type` and `style` properties in the block's definition](https://github.com/RaspberryPiFoundation/blockly/blob/1c280d10cc1dcad7d50a1678211871058d4e9cfb/blocks/logic.ts#L50). You will use the style class to assign the same colour to all of the logic blocks.

(If you were building blocks from scratch and wanted to avoid themes, you would assign this class with the `classes` property in the block definition. However, because these are standard blocks and they were built with themes in mind, using the style class works just as well.)

#### Choose an element to use

Next, you need to decide what element to use in your colour rule. The `<g>` element identifies the block but doesn't draw it. Instead, you can use the `<g>` element's first child. This is a `<path>` element with `fill` and `stroke` presentation attributes, which are easily overridden.

Note that different renderers use different numbers of `<path>` elements to
draw a block: Thrasos uses a single `<path>` element, Geras uses three `<path>`
elements, and Zelos uses one `<path>` for the outside of the block and one
`<path>` for each inline input.

#### Choose colours

The last step before writing your colour rules is to decide what colours to use. The Halloween theme in the themes codelab sets three colours:

```
    'logic_blocks': {
      'colourPrimary': "#8b4513",
      'colourSecondary':"#ff0000",
      'colourTertiary':"#c5eaff"
    },
```

How these colours are used depends on the renderer. The Thrasos renderer uses
the primary colour as the `fill` of the block, the tertiary colour as the
`stroke`, and the secondary colour as the `fill` when the block is a
[shadow block](/guides/configure/toolboxes/preset#shadow-blocks).

#### Add your rules

You're now ready to add your rules to set the `fill` and `stroke` of the logic blocks:

```css
/**********/
/* BLOCKS */
/**********/

/* LOGIC BLOCKS */

.logic_blocks > .blocklyPath {
  fill: #8b4513;
  stroke: #c5eaff;
}

.logic_blocks.blocklyShadow > .blocklyPath {
  fill: #ff0000;
  stroke: none;
}
```

Refresh your web page and open the **Logic** category. You should see that the
logic blocks are now rendered in autumnal brown instead of blue:

<Image
  src="/images/codelabs/css/blocks-logic.png"
  alt="A Blockly toolbox with the Logic category flyout open. The blocks in the flyout are brown."
  width="300px"
  className="codelabImage"
/>

### Disabled blocks

Your next step is to handle disabled blocks. Drag an `if do` block and any block from the **Loops** category onto the workspace. Right-click on each block and disable it using the context menu. Notice that the loop block has a cross-hatch pattern while the `if do` block does not:

<Image
  src="/images/codelabs/css/blocks-disabled-wrong.png"
  alt="An 'if do' block and a 'repeat 10 times' block, both of which are disabled. The 'if do' block is solid brown and the 'repeat 10 times' block has a cross-hatch pattern."
  className="codelabImage"
/>

This is because the rules you just added have the same specificity as the Blockly rules that set the cross-hatch pattern. (You can see this if you click on the `if do` block's `<path>` element and inspect its styles.) Because your rules occur later in the document, they take precedence. To use the standard CSS for disabled blocks, add a `:not(.blocklyDisabledPattern)` to your rules:

```css
/* LOGIC BLOCKS */

.logic_blocks:not(.blocklyDisabledPattern) > .blocklyPath {
  fill: #8b4513;
  stroke: #c5eaff;
}

.logic_blocks:not(.blocklyDisabledPattern).blocklyShadow > .blocklyPath {
  fill: #ff0000;
  stroke: none;
}
```

Refresh your page, drag the `if do` block onto the workspace, and disable it. It should now use the disabled pattern:

<Image
  src="/images/codelabs/css/blocks-disabled-right.png"
  alt="A disabled 'if do' block with a cross-hatch pattern."
  className="codelabImage"
/>
### Dropdown arrows

You now need to handle dropdown arrows. Drag a logic comparison block onto the workspace and look closely at the inverted triangle in the dropdown field -- it's blue even though the rest of the block is brown:

<Image
  src="/images/codelabs/css/blocks-arrow-wrong.png"
  alt="A brown logic comparison block with a blue dropdown arrow."
  className="codelabImage"
/>

If you look at the triangle with the element inspector, you'll see that it's a character in an SVG `<tspan>` element:

```
<body>
  <div class="blocklyDiv">
    <div class="injectionDiv">
      <svg class="blocklySvg">
        <g class="blocklyWorkspace">
          <g class="blocklyBlockCanvas">
            <g class="logic_compare">
              <g class="blocklyDropdownField">
                <text class="blocklyDropdownText">
                  <tspan style="fill: rgb(91, 128, 165);"> ▾</tspan>
```

You can also see that its colour is set with a `style` attribute, which can only be overridden with an `!important` declaration. To do this, add the following rules:

```css
.logic_blocks > .blocklyDropdownField .blocklyDropdownText tspan {
  fill: #8b4513 !important;
}

.logic_blocks.blocklyShadow > .blocklyDropdownField .blocklyDropdownText tspan {
  fill: #ff0000 !important;
}
```

Reload your page and drag the comparison block out again. The arrow should be the same colour as the rest of the block:

<Image
  src="/images/codelabs/css/blocks-arrow-right.png"
  alt="A brown logic comparison block with a brown dropdown arrow."
  className="codelabImage"
/>

### Loop, text, and list blocks

Your last step is to add similar rules for the loop, text, and list blocks:

```css
/* LOOP BLOCKS */

.loop_blocks:not(.blocklyDisabledPattern) > .blocklyPath {
  fill: #85e21f;
  stroke: #c5eaff;
}

.loop_blocks:not(.blocklyDisabledPattern).blocklyShadow > .blocklyPath {
  fill: #ff0000;
  stroke: none;
}

.loop_blocks > .blocklyDropdownField .blocklyDropdownText tspan {
  fill: #85e21f !important;
}

.loop_blocks.blocklyShadow > .blocklyDropdownField .blocklyDropdownText tspan {
  fill: #ff0000 !important;
}

/* TEXT BLOCKS */

.text_blocks:not(.blocklyDisabledPattern) > .blocklyPath {
  fill: #fe9b13;
  stroke: #c5eaff;
}

.text_blocks:not(.blocklyDisabledPattern).blocklyShadow > .blocklyPath {
  fill: #ff0000;
  stroke: none;
}

.text_blocks > .blocklyDropdownField .blocklyDropdownText tspan {
  fill: #fe9b13 !important;
}

.text_blocks.blocklyShadow > .blocklyDropdownField .blocklyDropdownText tspan {
  fill: #ff0000 !important;
}

/* LIST BLOCKS */

.list_blocks:not(.blocklyDisabledPattern) > .blocklyPath {
  fill: #4a148c;
  stroke: #cdb6e9;
}

.list_blocks:not(.blocklyDisabledPattern).blocklyShadow > .blocklyPath {
  fill: #ad7be9;
  stroke: none;
}

.list_blocks > .blocklyDropdownField .blocklyDropdownText tspan {
  fill: #4a148c !important;
}

.list_blocks.blocklyShadow > .blocklyDropdownField .blocklyDropdownText tspan {
  fill: #ad7be9 !important;
}
```

And that's it! Reload your page and explore the blocks in your Halloween-themed editor:

<Image
  src="/images/codelabs/css/final-workspace.png"
  alt="A Blockly editor in Halloween colors, the logic flyout open and various blocks on the workspace. The code and output divs are still the default colors."
  className="codelabImage"
/>

---

### Packages Docs Docs Codelabs Css Categories (`packages/docs/docs/codelabs/css/categories.mdx`)

---
title: Use CSS in Blockly - Toolbox Categories
description: Styling toolbox categories with CSS
---
import Image from '@site/src/components/Image';

# Use CSS in Blockly

## 5. Toolbox categories

In this section, you will create CSS rules to assign the colours used by the [categories section](/codelabs/theme-extension-identifier/customize-category-styles) of the themes codelab to the toolbox's categories.

### Identify the category element

Your first rule will set the colour of the **Logic** category. This rule needs to uniquely identify the element used by the **Logic** category, so open the developer tools and find the `blocklyToolboxCategory` `<div>` for the **Logic** category:

```
<body>
  <div class="blocklyDiv">
    <div class="injectionDiv">
      <div class="blocklyToolbox">
        <div class="blocklyToolboxCategoryGroup">
          <div class="blocklyToolboxCategoryContainer">
            <div class="blocklyToolboxCategory" id="blockly-1">
```

Unfortunately, the only thing that distinguishes this `<div>` from other category `<div>`s is a generated `id` attribute (`blockly-1`). This isn't stable enough to use in a CSS rule -- for example, if you switched the order of two categories you'd also have to switch the selectors in their rules.

To solve this problem, you'll need to add a class to the
`blocklyToolboxCategory` `<div>` for the **Logic** category. Open the
`toolbox.js` file and find the definition of the **Logic** category:

```js
    {
      kind: 'category',
      name: 'Logic',
      categorystyle: 'logic_category',
      contents: [...],
    },
```

The `categorystyle` property assigns a style that is used by a theme. Because
you're not using themes to assign category colours, you don't need the
`categorystyle` property. Delete it and add a `cssConfig` property that adds two
classes to the **Logic** category's `<div>`: `logic_category` uniquely
identifies the `<div>` and `blocklyToolboxCategory` is used by Blockly's CSS to
define rules that apply to all categories.

```js
    {
      kind: 'category',
      name: 'Logic',
      cssConfig: {
        row: 'blocklyToolboxCategory logic_category',
      },
      contents: [...],
    },
```

For a complete explanation of how `cssConfig` works, see [Custom CSS classes](/guides/configure/toolboxes/appearance#custom-css-classes) in the toolbox documentation.

### Add your rules

Next, add the following rules, which set the row colour and its colour when selected:

```css
/**************/
/* CATEGORIES */
/**************/

.logic_category {
  border-left: 8px solid #8b4513;
}

.logic_category.blocklyToolboxSelected {
  background-color: #8b4513 !important;
}
```

Refresh your web page and click the **Logic** category. The row is highlighted with your new colour:

<Image
  src="/images/codelabs/css/categories-logic.png"
  alt="A Blockly editor with the Logic category open. The category name is written in white on a brown background."
  className="codelabImage"
/>

### Update the other categories

Before you can write rules for the remaining categories, you need to replace `categorystyle` with `cssConfig` in each of their definitions:

```js
    {
      kind: 'category',
      name: 'Loops',
      cssConfig: {
        row: 'blocklyToolboxCategory loop_category',
      },
      contents: [...],
    },

    // Repeat for remaining categories
```

Next, add the following rules to `halloween.css`. These rules use the colours from themes codelab for the **Loops**, **Text**, and **Lists** categories and the colours from the Classic theme (the default theme) for the **Math**, **Variables**, and **Functions** categories.

```css
.loop_category {
  border-left: 8px solid #85e21f;
}

.loop_category.blocklyToolboxSelected {
  background-color: #85e21f !important;
}

.math_category {
  border-left: 8px solid #5b67a5;
}

.math_category.blocklyToolboxSelected {
  background-color: #5b67a5 !important;
}

.text_category {
  border-left: 8px solid #fe9b13;
}

.text_category.blocklyToolboxSelected {
  background-color: #fe9b13 !important;
}

.list_category {
  border-left: 8px solid #4a148c;
}

.list_category.blocklyToolboxSelected {
  background-color: #4a148c !important;
}

.variable_category {
  border-left: 8px solid #a55b80;
}

.variable_category.blocklyToolboxSelected {
  background-color: #a55b80 !important;
}

.procedure_category {
  border-left: 8px solid #b88cc0;
}

.procedure_category.blocklyToolboxSelected {
  background-color: #b88cc0 !important;
}
```

Refresh your web page. You should see the new colours beside each category:

<Image
  src="/images/codelabs/css/categories-halloween.png"
  alt="A Blockly toolbox with Halloween colours next to each category."
  className="codelabImage"
/>

---

### Packages Docs Docs Codelabs Css Components (`packages/docs/docs/codelabs/css/components.mdx`)

---
title: Use CSS in Blockly - Components
description: Styling Blockly components with CSS
---
import Image from '@site/src/components/Image';

# Use CSS in Blockly

## 4. Components

In this section, you will create CSS rules to assign the colours used by the [components section](/codelabs/theme-extension-identifier/customize-components) of the themes codelab to various components.

To start, create a file in the `src/` folder named `halloween.css` and import it in `src/index.js`, after the existing `index.css` import:

```js
import './index.css';
import './halloween.css';
```

### Main workspace colour

Your first rule will set the background colour of the main workspace. In your Blockly editor, find the `<rect>` element with the `blocklyMainBackground` class:

```
<body>
  <div class="blocklyDiv">
    <div class="injectionDiv">
      <svg class="blocklySvg">
        <g class="blocklyWorkspace">
          <rect class="blocklyMainBackground">
```

This seems like a good target for your rule, except that the `fill` property is already used to set the grid pattern. Instead, we'll set the `background-color` property of the `blocklySvg` element. To do this, add the following rule to `halloween.css`:

```css
/**************/
/* COMPONENTS */
/**************/

.blocklySvg {
  background-color: #ff7518;
}
```

Refresh your page and notice that the workspace background is now orange:

<Image
  src="/images/codelabs/css/components-workspace.png"
  alt="The Blockly sample app, now with an orange background on the Blockly workspace."
  className="codelabImage"
/>

:::note
The visual changes in this codelab will not affect the appearance of the code generation or code output panes, 
since they are not part of Blockly's workspace. To change the appearance of these panes, you can modify `index.css`.
:::

### Mutator workspace colour

Now drag an `if do` block onto the workspace and click the mutator (gear) icon. Notice that the mutator workspace's background colour is unchanged. This is because it's a different workspace. See if you can find the `<rect>` that draws the mutator workspace. (Here's a hint: It's on the bubble canvas, which is where the bubbles used by mutators, comments, and warnings are drawn.)

Don't worry if you didn't find it right away -- Blockly's DOM tree is fairly complex:

```
<body>
  <div class="blocklyDiv">
    <div class="injectionDiv">
      <svg class="blocklySvg">
        <g class="blocklyWorkspace">
          <g class="blocklyBubbleCanvas">
            <g class="blocklyMiniWorkspaceBubble">
              <g>
                <svg>
                  <g class="blocklyWorkspace">
                    <rect class="blocklyMutatorBackground">
```

Next, add a CSS rule to set the workspace's background colour:

```css
.blocklyMutatorBackground {
  fill: #ff7518;
}
```

To see your new colours, reload the web page, drag the `if do` block out again,
and reopen the mutator. You should see that the mutator workspace background
colour is orange, matching the main workspace background:

<Image
  src="/images/codelabs/css/components-mutator.png"
  alt="An 'if do' block with a mutator that has an orange background."
  className="codelabImage"
/>

### Other component colours

Themes allow you to define the colours of many (but not all) components. The following table shows what classes and properties to use to set the same colours as the component styles in themes:

| Component style             | Selectors (properties)                                                                               |
| --------------------------- | ---------------------------------------------------------------------------------------------------- |
| `workspaceBackgroundColour` | `.blocklySvg (background-color)`, `.blocklyMutatorBackground (fill)`                                 |
| `toolboxBackgroundColour`   | `.blocklyToolbox (background-color)`                                                                 |
| `toolboxForegroundColour`   | `.blocklyToolbox (color)`                                                                            |
| `flyoutBackgroundColour`    | `.blocklyFlyoutBackground (fill)`                                                                    |
| `flyoutForegroundColour`    | `.blocklyFlyoutLabel > .blocklyFlyoutLabelText (fill)`, `.blocklyFlyoutButton > .blocklyText (fill)` |
| `flyoutOpacity`             | `.blocklyFlyoutBackground (fill-opacity)`                                                            |
| `scrollbarColour`           | `.blocklyScrollbarHandle (fill)`                                                                     |
| `scrollbarOpacity`          | `.blocklyScrollbarHandle (fill-opacity)`                                                             |
| `insertionMarkerColour`     | `.blocklyInsertionMarker > .blocklyPath (fill)`                                                      |
| `insertionMarkerOpacity`    | `.blocklyInsertionMarker > .blocklyPath (fill-opacity)`                                              |

Add the following rules to `halloween.css`:

```css
.blocklyToolbox {
  background-color: #f9c10e;
  color: #fff;
}

.blocklyFlyoutBackground {
  fill: #252526;
  fill-opacity: 1;
}

.blocklyFlyoutLabel > .blocklyFlyoutLabelText {
  fill: #ccc !important;
}

.blocklyFlyoutButton > .blocklyText {
  fill: #ccc !important;
}

.blocklyScrollbarHandle {
  fill: #ff0000;
  fill-opacity: 0.4;
}

.blocklyInsertionMarker > .blocklyPath {
  fill: #fff !important;
  fill-opacity: 0.3 !important;
  stroke: none;
}
```

Now reload your page. You should now see a yellow toolbox and red scrollbars:
<Image
  src="/images/codelabs/css/components-halloween.png"
  alt="A Blockly editor with Halloween colors: a yellow toolbox, orange workspace, and red scrollbars."
  className="codelabImage"
/>

### fill vs background-color

You might have noticed that some rules use `background-color` and `color` and
others use `fill` and `stroke`. This is because `background-color` and `color`
apply to HTML elements, like the `<div>` used by the toolbox, and `fill` and
`stroke` apply to most SVG elements, like the `<path>` used by the flyout
background. (An exception to this is the top-level `<svg>` element that contains
Blockly, which uses `background-color` and `color`.)

### The !important declaration

You might have also noticed that some rules use an `!important` declaration while others don't. This is because Blockly sets colours in several different ways, some of which are easily overridden and some of which aren't.

- **Presentation attributes:** These are attributes on SVG elements, such as `fill` and `stroke`. They have a specificity of 0 and are overridden by any rules you write. As you will see later, block colours use presentation attributes.

- **`<style>` tags:** Many of Blockly's CSS rules are included via two `<style>` tags at the start of the `<head>` tag. Your rules override these if they have the same or higher specificity. For example, the rule for `.blocklyScrollbarHandle` has the same specificity as Blockly's rule for this class, but overrides Blockly's rule because it occurs later in the document. On the other hand, the rule for `.blocklyFlyoutLabel > .blocklyFlyoutLabelText` has a lower specificity than Blockly's rule and must override it with an `!important` declaration.

- **Inline styles:** These rules are included via a `style` attribute and can only be overridden by an `!important` declaration. As you will see later, the colour of the arrow in a dropdown field is set with an inline style and must be overridden with `!important`.

The easiest way to determine how a rule is set is to highlight the appropriate element in the element inspector and look at the corresponding style information. In a few cases, this isn't possible. For example, an insertion marker is created only when you drag a child near its parent and is deleted when you let go of the parent to highlight the insertion marker's element. In these cases, you will need to [search Blockly's rules](/guides/configure/appearance/css#blockly-css-rules).

---

### Packages Docs Docs Codelabs Css Setup (`packages/docs/docs/codelabs/css/setup.mdx`)

---
description: Setting up the "Use CSS in Blockly" codelab.
---

import Image from '@site/src/components/Image';

# Use CSS in Blockly

## 2. Setup

### Create the application

Use the [`npx @blockly/create-package app`](https://www.npmjs.com/package/@blockly/create-package) command to create a standalone application that contains a sample setup of Blockly, including custom blocks and a display of the generated code and output.

1. Run `npx @blockly/create-package app css-codelab` in your terminal. This will create a Blockly application in the folder `css-codelab`.
1. Use `cd` to move into the new directory: `cd css-codelab`.
1. Run `npm start` to start the server and run the sample application.
1. The sample app will automatically run in the browser window that opens.

The local address in the address bar of your browser starting with `http://localhost:` shows where your app is.
If you accidentally close this window or tab, you can re-open this local address to view the app as long as `npm start` is still running.

The initial application uses the default theme and a plain toolbox, and contains no custom CSS.

<Image
  src="/images/codelabs/css/setup-starter.png"
  alt="A Blockly workspace with an output pane and a toolbox with multiple categories, all in the default theme."
  className="codelabImage"
/>

### Change the storage key

Before setting up the rest of the application, **change the storage key** used for this codelab application. This will ensure that the workspace is saved in its own storage, separate from the regular sample app, so that it doesn't interfere with other demos.
In `src/serialization.js`, change the value of `storageKey` to some unique string. `cssWorkspace` will work:

```js
// Use a unique storage key for this codelab
const storageKey = 'cssWorkspace';
```

### Explore the starter code

Take a moment to explore the code you just created in the `css-codelab` folder. If you'd like a more in-depth explanation of all of the code in the sample app, check out the [getting started codelab](/codelabs/getting-started/codelab-overview) which goes through creating this sample app from scratch.

For a briefer outline of the code, visit the [sample app overview](/guides/get-started/sample-app-overview/) page for an overview of the included files and tooling.

The pieces that matter most for this codelab are:

- `src/toolbox.js` - defines the toolbox's categories. You'll add a CSS class to each category so you can target it with a CSS rule.
- `src/index.js` - injects the workspace. You'll import your new stylesheet here.

---

### Packages Docs Docs Codelabs Css Summary (`packages/docs/docs/codelabs/css/summary.mdx`)

---
pagination_next: null
title: Use CSS in Blockly - Summary
description: Summary of the CSS in Blockly codelab
---

## 7. Summary

In this codelab, you learned how to use CSS to set the colours of your Blockly editor.

You can find the code for the
[completed CSS codelab](https://github.com/RaspberryPiFoundation/blockly/tree/main/packages/docs/docs/codelabs/css/complete-code)
on GitHub.

For more information, see [Style with CSS](/guides/configure/appearance/css) in the Blockly user guides.

---

### Packages Docs Docs Codelabs Css Tour (`packages/docs/docs/codelabs/css/tour.mdx`)

---
title: Use CSS in Blockly - A tour of Blockly's elements
description: Explore Blockly's HTML and SVG elements in the CSS codelab
---

import Image from '@site/src/components/Image';

# Use CSS in Blockly

## 3. A tour of Blockly's elements

In this section, you'll explore the HTML and SVG elements used by Blockly, as well as the classes assigned to these elements.

In your Blockly editor, drag a `count with` block from the **Loops** category and an `if do` block from the **Logic** category onto your workspace and open your browser's [developer tools](https://developer.mozilla.org/en-US/docs/Learn_web_development/Howto/Tools_and_setup/What_are_browser_developer_tools). Your screen should look something like this:

<Image
  src="/images/codelabs/css/tour-dev-tools.png"
  alt="A Blockly editor with two blocks on the workspace and the developer tools open."
  className="codelabImage"
/>

Using the element inspector, explore the elements used by Blockly. For example, see if you can find the SVG `<path>` element used to draw the `count with` block. If you're having trouble finding things, the following outline might help. (Note that it omits some elements and most attributes.)

```
/* Detailed source-code truncated for AI context efficiency. */
```

One thing that's important to notice are the `blocklyXxxx` classes assigned to most elements. These explain how Blockly uses each element and will be the targets of many of your CSS rules. If you look closely, you'll notice that many elements have multiple classes -- for example, the `<g>` element for the dropdown field in the `counts with` block has `blocklyField`, `blocklyDropdownField`, `blocklyVariableField`, and `blocklyEditableField` classes. Having multiple classes allows you to write CSS rules that affect different ranges of elements.

---

### Packages Docs Docs Codelabs Custom Generator Array Block Generator (`packages/docs/docs/codelabs/custom-generator/array-block-generator.mdx`)

---
description: How to write a block code generator that creates an array.
---

# Build a custom generator

## 7. Array block generator

This step will build the generator for the array block. You will learn how to indent code and handle a variable number of inputs.

The array block uses a mutator to dynamically change the number of inputs it has.



The generated code looks like:

```json
[1, "two", false, true]
```

As with member blocks, there are no restrictions on the types of blocks connected to inputs.

### Gather values

Each value input on the block has a name: `ADD0`, `ADD1`, etc. Use `valueToCode` in a loop to build an array of values:

```js
const values = [];
for (let i = 0; i < block.itemCount_; i++) {
  const valueCode = generator.valueToCode(block, 'ADD' + i, Order.ATOMIC);
  if (valueCode) {
    values.push(valueCode);
  }
}
```

Notice that the code skips empty inputs by checking if `valueCode` is `null`.

To include empty inputs, use the string `'null'` as the value:

```js
const values = [];
for (let i = 0; i < block.itemCount_; i++) {
  const valueCode =
    generator.valueToCode(block, 'ADD' + i, Order.ATOMIC) || 'null';
  values.push(valueCode);
}
```

### Format

At this point `values` is an array of `string`s. The strings contain the generated code for each input.

Convert the list into a single `string`, with a comma and newline separating each element:

```js
const valueString = values.join(',\n');
```

Next, use `prefixLines` to add indentation at the beginning of each line:

```js
const indentedValueString = generator.prefixLines(
  valueString,
  generator.INDENT,
);
```

`INDENT` is a property on the generator. It defaults to two spaces, but language generators may override it to increase indent or change to tabs.

Finally, wrap the indented values in brackets and return the string:

```js
const codeString = '[\n' + indentedValueString + '\n]';
return [codeString, Order.ATOMIC];
```

### Putting it all together

Here is the final array block generator:

```js
jsonGenerator.forBlock['lists_create_with'] = function (block, generator) {
  const values = [];
  for (let i = 0; i < block.itemCount_; i++) {
    const valueCode = generator.valueToCode(block, 'ADD' + i, Order.ATOMIC);
    if (valueCode) {
      values.push(valueCode);
    }
  }
  const valueString = values.join(',\n');
  const indentedValueString = generator.prefixLines(
    valueString,
    generator.INDENT,
  );
  const codeString = '[\n' + indentedValueString + '\n]';
  return [codeString, Order.ATOMIC];
};
```

### Test it

Test the block generator by adding an array to the onscreen blocks and populating it.

What code does it generate if there are no inputs?

What if there are five inputs, one of which is empty?

---

### Packages Docs Docs Codelabs Custom Generator Generating A Stack (`packages/docs/docs/codelabs/custom-generator/generating-a-stack.mdx`)

---
description: How to generate code for the blocks in a stack.
---

# Build a custom generator

## 9. Generating a stack

### The scrub\_ function

The `scrub_` function is called on every block from `blockToCode`. It takes in three arguments:

- `block` is the current block.
- `code` is the code generated for this block, which includes code from all attached value blocks.
- `opt_thisOnly` is an optional `boolean`. If true, code should be generated for this block but no subsequent blocks.

By default, `scrub_` simply returns the passed-in code. A common pattern is to override the function to also generate code for any blocks that follow the current block in a stack. In this case, the code will add commas and newlines between object members:

```js
jsonGenerator.scrub_ = function (block, code, thisOnly) {
  const nextBlock = block.nextConnection && block.nextConnection.targetBlock();
  if (nextBlock && !thisOnly) {
    return code + ',\n' + jsonGenerator.blockToCode(nextBlock);
  }
  return code;
};
```

### Testing scrub\_

Create a stack of `member` blocks on the workspace. There should be generated code for all of the blocks, not just the first one.

Next, add an `object` block and drag the `member` blocks into it. This case tests `statementToCode`, and should generate code for all of of the blocks.

---

### Packages Docs Docs Codelabs Custom Generator Member Block Generator (`packages/docs/docs/codelabs/custom-generator/member-block-generator.mdx`)

---
description: How to write a block code generator using field and input values.
---

# Build a custom generator

## 6. Member block generator

This step will build the generator for the `member` block. It will use the function `getFieldValue`, and introduce the function `valueToCode`.

The member block has a text input field and a value input.



The generated code looks like `"property name": "property value"`.

### Field value

The **property name** is the value of the text input, which is fetched via `getFieldValue`:

```js
const name = block.getFieldValue('MEMBER_NAME');
```

Recall: the name of the value being fetched is `MEMBER_NAME` because that is how it was defined in `src/blocks/json.js`.

### Input value

The **property value** is whatever is attached to the value input. A variety of blocks could be attached there: `logic_null`, `text`, `math_number`, `logic_boolean`, or even an array (`lists_create_with`). Use `valueToCode` to get the correct value:

```js
const value = generator.valueToCode(block, 'MEMBER_VALUE', Order.ATOMIC);
```

`valueToCode` does three things:

- Finds the blocks connected to the named value input (the second argument)
- Generates the code for that block
- Returns the code as a string

If no block is attached, `valueToCode` returns `null`. In another generator, `valueToCode` might need to replace `null` with a different default value; in JSON, `null` is fine.

The third argument is related to operator precedence. It is used to determine if parentheses need to be added around the value. In JSON, parentheses will never be added, as discussed in an earlier section.

### Build the code string

Next, assemble the arguments `name` and `value` into the correct code, of the form `"name": value`.

```js
const code = `"${name}": ${value}`;
```

### Put it all together

All together, here is block generator for the member block:

```js
jsonGenerator.forBlock['member'] = function (block, generator) {
  const name = block.getFieldValue('MEMBER_NAME');
  const value = generator.valueToCode(block, 'MEMBER_VALUE', Order.ATOMIC);
  const code = `"${name}": ${value}`;
  return code;
};
```

---

### Packages Docs Docs Codelabs Custom Generator Object Block Generator (`packages/docs/docs/codelabs/custom-generator/object-block-generator.mdx`)

---
description: How to write a block code generator that creates an object.
---

# Build a custom generator

## 8. Object block generator

This section will write the generator for the `object` block and will demonstrate how to use `statementToCode`.

The `object` block generates code for a JSON Object. It has a single statement input, in which member blocks may be stacked.



The generated code looks like this:

```json
{
  "a": true,
  "b": "one",
  "c": 1
}
```

### Get the contents

We'll use `statementToCode` to get the code for the blocks attached to the statement input of the `object` block.

`statementToCode` does three things:

- Finds the first block connected to the named statement input (the second argument)
- Generates the code for that block
- Returns the code as a string

In this case the input name is `'MEMBERS'`.

```js
const statement_members = generator.statementToCode(block, 'MEMBERS');
```

### Format and return

Wrap the statements in curly brackets and return the code, using the default precedence:

```js
const code = '{\n' + statement_members + '\n}';
return [code, Order.ATOMIC];
```

Note that `statementToCode` handles the indentation automatically.

### Test it

Here is the full block generator:

```js
jsonGenerator.forBlock['object'] = function (block, generator) {
  const statementMembers = generator.statementToCode(block, 'MEMBERS');
  const code = '{\n' + statementMembers + '\n}';
  return [code, Order.ATOMIC];
};
```

Test it by generating code for an `object` block containing a single `member` block. The result should look like this:

```json
{
  "test": true
}
```

Next, add a second member block and rerun the generator. Did the resulting code change? Let's look at the next section to find out why not.

---

### Packages Docs Docs Codelabs Custom Generator Setup (`packages/docs/docs/codelabs/custom-generator/setup.mdx`)

---
description: Setting up the "Build a custom generator" codelab.
---

import Image from '@site/src/components/Image';

# Build a custom generator

## 2. Setup

This codelab will demonstrate how to add code to the Blockly sample app to create and use a new generator.

### The application

Use the [`npx @blockly/create-package app`](https://www.npmjs.com/package/@blockly/create-package) command to create a standalone application that contains a sample setup of Blockly, including custom blocks and a display of the generated code and output.

1. Run `npx @blockly/create-package app custom-generator-codelab`. This will create a blockly application in the folder `custom-generator-codelab`.
1. `cd` into the new directory: `cd custom-generator-codelab`.
1. Run `npm start` to start the server and run the sample application.
1. The sample app will automatically run in the browser window that opens.

The initial application has one custom block and includes JavaScript generator definitions for that block. Since this codelab will be creating a JSON generator instead, it will remove that custom block and add its own.

### Change the storage key

Before setting up the rest of the application, change the storage key used for this codelab application. This will ensure that the workspace is saved in its own storage, separate from the regular sample app, so that it doesn't interfere with other demos. 

In `serialization.js`, change the value of `storageKey` to some unique string. `jsonGeneratorWorkspace` will work:

```js
// Use a unique storage key for this codelab
const storageKey = 'jsonGeneratorWorkspace';
```

### Explore the starter code

Take a moment to explore the code you just created in the `custom-generator-codelab` folder. If you'd like a more in-depth explanation of all of the code in the sample app, check out the [getting started codelab](/codelabs/getting-started/codelab-overview) which goes through creating this sample app from scratch.

For a briefer outline of the code, visit the [sample app overview](/guides/get-started/sample-app-overview/) page for an overview of the included files and tooling.

### Blocks

This codelab will use two custom blocks, as well as five blocks from Blockly's standard set.

The custom blocks represent the _Object_ and _Member_ sections of the JSON specification.

The blocks are:

- `object`
- `member`
- `math_number`
- `text`
- `logic_boolean`
- `logic_null`
- `lists_create_with`

### Custom block definitions

Create a new file in the `src/blocks/` directory called `json.js`. This will hold the custom JSON-related blocks. Add the following code:

```js
import * as Blockly from 'blockly';

export const blocks = Blockly.common.createBlockDefinitionsFromJsonArray([
  {
    type: 'object',
    message0: '{ %1 %2 }',
    args0: [
      {
        type: 'input_dummy',
      },
      {
        type: 'input_statement',
        name: 'MEMBERS',
      },
    ],
    output: null,
    colour: 230,
  },
  {
    type: 'member',
    message0: '%1 %2 %3',
    args0: [
      {
        type: 'field_input',
        name: 'MEMBER_NAME',
        text: '',
      },
      {
        type: 'field_label',
        name: 'COLON',
        text: ':',
      },
      {
        type: 'input_value',
        name: 'MEMBER_VALUE',
      },
    ],
    previousStatement: null,
    nextStatement: null,
    colour: 230,
  },
]);
```

This code creates the block definitions, but it doesn't register the definitions with Blockly to make the blocks usable. We'll do that in `src/index.js`.
Currently, the app imports `blocks` from the original sample file, `text.js`. Instead, it should import the definitions that were just added. Remove the original import:

```js
// Remove this!
import { blocks } from './blocks/text';
```

and add the import for the new blocks:

```js
import { blocks } from './blocks/json';
```

Later in the file the block definitions are registered with Blockly (this code is already present and does not need to be added):

```js
Blockly.common.defineBlocks(blocks);
```

### Toolbox definition

Next, define a toolbox that includes these custom blocks. For this example, there's a flyout-only toolbox with seven blocks in it.

The file `src/toolbox.js` contains the original sample toolbox. Replace the entire contents of that file with this code:

```js
export const toolbox = {
  kind: 'flyoutToolbox',
  contents: [
    {
      kind: 'block',
      type: 'object',
    },
    {
      kind: 'block',
      type: 'member',
    },
    {
      kind: 'block',
      type: 'math_number',
    },
    {
      kind: 'block',
      type: 'text',
    },
    {
      kind: 'block',
      type: 'logic_boolean',
    },
    {
      kind: 'block',
      type: 'logic_null',
    },
    {
      kind: 'block',
      type: 'lists_create_with',
    },
  ],
};
```

Our `index.js` file already handles importing the toolbox and using it in Blockly.

If the server is already running, refresh the page to see changes. Otherwise, run `npm start` to start the server. New blocks should now exist in the toolbox, like this:

<Image
  src="/images/codelabs/custom-generator/toolbox_blocks.png"
  alt="Screenshot of toolbox showing the added blocks, including the new member and object blocks, plus the built-in number, text, boolean, null, and list blocks."
  className="codelabImage"
/>

The app is still trying to generate and run JavaScript for the workspace, instead of JSON. We will change that soon.

---

### Packages Docs Docs Codelabs Custom Generator Summary (`packages/docs/docs/codelabs/custom-generator/summary.mdx`)

---
pagination_next: null
description: Summary of the "Build a custom generator" codelab.
---

# Build a custom generator

## 10. Summary

In this codelab you learned:

- How to build a custom language generator to generate JSON.
- How to define block generators for built in blocks and for custom blocks.
- How to use a custom generator in a sample app.
- How to use the core generator functions: `statementToCode`, `valueToCode`, `blockToCode`, and `getFieldValue`.
- How to generate code for stacks of blocks.

JSON is a simple language, and there are many additional features that could be implemented in a custom generator. Blockly's built-in language generators are a good place to learn more about some additional features:

- Variable definition and use.
- Function definition and use.
- Initialization and cleanup.
- Injecting additional functions and variables.
- Handling comments.
- Handling parentheses with operator precedence.

Blockly ships with five language generators: Python, Dart, JavaScript, PHP, and Lua. The language generators and block generators can be found in the [generators directory](https://github.com/RaspberryPiFoundation/blockly/tree/main/generators).

---

### Packages Docs Docs Codelabs Custom Generator The Basics (`packages/docs/docs/codelabs/custom-generator/the-basics.mdx`)

---
description: How to define and call a language generator.
---

# Build a custom generator

## 3. The basics

A _language generator_ defines the basic properties of a language, such as how indentation works. _Block generators_ define how individual blocks are turned into code, and must be defined for every block used.

A language generator has a single entry point: `workspaceToCode`. This function takes in a workspace and:

- Initializes the generator and any necessary state by calling `init`.
- Walks the list of top blocks on the workspace and calls `blockToCode` on each top block.
- Cleans up any leftover state by calling `finish`.
- Returns the generated code.

### Create the language generator

The first step is to define and call the custom language generator.

A custom language generator is simply an instance of `Blockly.Generator`. Create a new file `src/generators/json.js`. In it, import Blockly and call the `Blockly.Generator` constructor, passing in the generator's name and storing the result.

```js
import * as Blockly from 'blockly';

export const jsonGenerator = new Blockly.CodeGenerator('JSON');
```

### Generate code

Next, hook up the new generator with the sample app. First, remove the old code that imports the new block generator properties and assigns them to the `javascriptGenerator`. Remove these lines from `src/index.js`:

```js
// Remove these lines!
import { forBlock } from './generators/javascript';
import { javascriptGenerator } from 'blockly/javascript';

// Also remove this line! (further down)
Object.assign(javascriptGenerator.forBlock, forBlock);
```

Now import the new generator:

```js
import { jsonGenerator } from './generators/json';
```

Currently, there are two panels in the app next to the workspace. One shows the generated JavaScript code, and one executes it. The one panel showing the generated Javascript code will be changed to show the generated JSON code instead. Since JSON can't be directly executed, the panel that shows the execution will be left blank. Change the `runCode` function to the following:

```js
// This function resets the code div and shows the
// generated code from the workspace.
const runCode = () => {
  const code = jsonGenerator.workspaceToCode(ws);
  codeDiv.innerText = code;
};
```

Since the bottom panel is not being modified, delete this line:

```js
// Remove this line!
const outputDiv = document.getElementById('output');
```

The generated code will now be shown automatically in the top left panel. Refresh the sample app page to see the changes so far.

### Test it

Put a number block on the workspace and check the generator output area. It's empty, so check the console. You should see an error:

```
Language "JSON" does not know how to generate code for block type "math_number".
```

This error occurs because there has to be a block generator for each type of block. Read the next section for more details.

---

### Packages Docs Docs Codelabs Custom Generator Value Block Generators (`packages/docs/docs/codelabs/custom-generator/value-block-generators.mdx`)

---
description: How to write a block code generator for a simple value block.
---

import Image from '@site/src/components/Image';

# Build a custom generator

## 5. Value block generators

This step will build the generators for the simple value blocks: `logic_null`, `text`, `math_number`, and `logic_boolean`.

It will use `getFieldValue` on several types of fields.

### Null

The simplest block in this example is the `logic_null` block.

<Image
  src="/images/codelabs/custom-generator/null_block.png"
  alt='The null block simply returns "null".'
  className="codelabImage"
/>

No matter what, it generates the code `'null'`. Notice that this is a string, because all generated code is a string.
Add the following code to `src/generators/json.js`:

```js
jsonGenerator.forBlock['logic_null'] = function (block) {
  return ['null', Order.ATOMIC];
};
```

### String

Next is the `text` block.

<Image
  src="/images/codelabs/custom-generator/text_block.png"
  alt="The text block has an input for the user to type text into."
  className="codelabImage"
/>

Unlike `logic_null`, there is a single text input field on this block. Use `getFieldValue`:

```js
const textValue = block.getFieldValue('TEXT');
```

Since this is a string in the generated code, wrap the value in quotation marks and return it:

```js
jsonGenerator.forBlock['text'] = function (block) {
  const textValue = block.getFieldValue('TEXT');
  const code = `"${textValue}"`;
  return [code, Order.ATOMIC];
};
```

### Number

The `math_number` block has a number field.

<Image
  src="/images/codelabs/custom-generator/number_block.png"
  alt="The number block has an input for a user to type a number"
  className="codelabImage"
/>

Like the `text` block, the `math_number` block can use `getFieldValue`. Unlike the text block, the function doesn't need to wrap it in additional quotation marks, because in the JSON code, it won't be a string.

However, like all generated code and as with `null` above, the function needs to return the code as a string from the generator.

```js
jsonGenerator.forBlock['math_number'] = function (block) {
  const code = String(block.getFieldValue('NUM'));
  return [code, Order.ATOMIC];
};
```

### Boolean

The `logic_boolean` block has a dropdown field named `BOOL`.

<Image
  src="/images/codelabs/custom-generator/boolean_block.png"
  alt="The boolean block lets the user select 'true' or 'false' from a dropdown menu."
  className="codelabImage"
/>

Calling `getFieldValue` on a dropdown field returns the value of the selected option, which may not be the same as the display text. In this case the dropdown has two possible values: `TRUE` and `FALSE`.

```js
jsonGenerator.forBlock['logic_boolean'] = function (block) {
  const code = block.getFieldValue('BOOL') === 'TRUE' ? 'true' : 'false';
  return [code, Order.ATOMIC];
};
```

### Summary

- Value blocks return an array containing the value as a string and the precedence.
- `getFieldValue` finds the field with the specified name and returns its value.
- The type of the return value from `getFieldValue` depends on the type of the field.
- Each field type must document what its value represents.

---

### Packages Docs Docs Codelabs Custom Mutator Code Generation (`packages/docs/docs/codelabs/custom-mutator/code-generation.mdx`)

---
description:  Generating code for the mutator.
---

import Image from '@site/src/components/Image';

# Build a custom mutator

## 7. Generating code 

Now, it's time to revisit the [block-code generator](https://docs.blockly.com/guides/create-custom-blocks/code-generation/block-code/)
in `javascript.js`. Since the sample app displays JavaScript code, you'll make a 
generator for JavaScript. 

### Update the code generator

Update the `resizable_list` generator in `javascript.js` to contain the 
following code: 

```js
forBlock['resizable_list'] = function (block, generator) {
  // Create a list with any number of elements of any type.
  const elements = new Array(block.itemCount);
  for (let i = 0; i < block.itemCount; i++) {
    elements[i] = generator.valueToCode(block, 'ADD' + i, Order.NONE) || 'null';
  }
  const code = '[' + elements.join(', ') + ']';
  return [code, Order.ATOMIC];
};
```

This code generator converts each input to code, then comma-separates the list 
and joins them all between two brackets. This is how a block like this: 

<Image
  src="/images/codelabs/custom-mutator/code_block.png"
  alt="A list block with three inputs: the first is the integer 123, the second is empty, the third is a string that says 'Hello, world!'"
  className="codelabImage"
/>

Generates this code: 

```js
[123, null, 'Hello, world!'];
```

### Test it

Test your mutator by dragging it into the workspace, right clicking, and 
adding an input. You may notice something strange. Although the block generates 
code when it first enters the workspace, adding a new input does not update the 
code. 

Now try moving the list block. The code window will be updated. 

### Why doesn't the code update immediately? 

In the sample app, a function called `runCode()` handles generating the code 
for the code window. A [change listener](https://docs.blockly.com/guides/configure/events/#listen-to-events-from-the-workspace) 
in `index.js` calls `runCode()` when certain types of events are detected. 

This means that when blocks are changed, moved, or added, an event is fired and 
the code is regenerated. However, the new mutator does not fire any events, so adding 
or removing an input is not enough to cause the code to be regenerated. In order for the code 
to be regenerated, a different event has to occur (like moving the block).

The next step will address this issue by adding a function to the mutator that 
fires an event when the number of inputs are changed.

---

### Packages Docs Docs Codelabs Custom Mutator Create The Mutator (`packages/docs/docs/codelabs/custom-mutator/create-the-mutator.mdx`)

---
description:  How to create and register a mutator that saves and loads extra state.
---

# Build a custom mutator

## 4. Create the mutator

Since mutators contain extra state, this extra state needs to be serialized and 
deserialized with the rest of the state of the block. Although mutators can 
vary greatly, any mutator requires [serialization hooks](https://docs.blockly.com/guides/create-custom-blocks/mutators/#serialization-hooks). 

### Create the mutator mixin object

Create a new folder called `mutators`, then create a file in that folder called 
`list_mutator.js`. In `list_mutator.js`, import Blockly, then create an empty object:

```js
import * as Blockly from 'blockly/core';

// The mutator mixin
export const LIST_MUTATOR = { 
    // Add mutator functions here 
};
```

The `LIST_MUTATOR` will be the mixin object for the custom mutator. 

### Serialize

The mutator must serialize the extra state of the block. This is accomplished by 
implementing the function `saveExtraState()`. Since this codelab implements a 
list mutator, you can use the same `saveExtraState()` code as the default 
`lists_create_with` block. This function should return a JSON serializable value.

Add the following code to the `LIST_MUTATOR` object:

```js
export const LIST_MUTATOR = {
    saveExtraState: function() {
        return {
            'itemCount': this.itemCount,
        };
    },
};
```

### Deserialize

The mutator mixin must also load, or deserialize, the extra state of the block. 
To deserialize, `loadExtraState()` reads in the `itemCount` value from the 
`state` of the block. 

Add the following code to the `LIST_MUTATOR`, just after `saveExtraState()`:

```js
loadExtraState: function(state) {
    this.itemCount = state['itemCount'];
},
```

### Register the mutator

Now, register the mutator with [`Blockly.Extensions.registerMutator`](https://docs.blockly.com/reference/namespaces/Extensions/functions/registerMutator/). 
This function requires a string name and a mixin object as parameters. It also 
takes two optional parameters: 
- A function which runs after the mixin functions are added to the block.
- A list of blocks to include in the mutator flyout, if you are using the default 
mutator UI. This parameter is not applicable in this codelab, since you will be 
creating a custom UI. 

In this case, the optional function is a great way to initialize the number of 
list items in the mutator. Since the block starts with one input (see the 
[block definition](/codelabs/custom-mutator/the-basics#create-the-custom-block)), you'll set a variable on the block
called `itemCount` to 1.

Add the following import and registration to `index.js`: 

```js {1,9-13}
import {LIST_MUTATOR} from './mutators/list_mutator';

...

// Register the blocks and generator with Blockly
Blockly.common.defineBlocks(blocks);
Blockly.common.defineBlocks(mutatorBlocks); 
Object.assign(javascriptGenerator.forBlock, forBlock);
Blockly.Extensions.registerMutator(
  'list_mutator', 
  LIST_MUTATOR, 
  function() { this.itemCount = 1; }
);
```

### Add the mutator to the block

Now that the mutator is registered, add it to the block definition in `list.js`:

```js {14}
const resizableListBlock = {
  type: 'resizable_list',
  message0: 'resizable list with %1',
  args0: [
    {
      type: 'input_value',
      name: 'ADD0',
    }
  ],
  output: null,
  style: "list_blocks",
  tooltip: '',
  helpUrl: '',
  mutator: 'list_mutator',
};
```

---

### Packages Docs Docs Codelabs Custom Mutator Custom Ui (`packages/docs/docs/codelabs/custom-mutator/custom-ui.mdx`)

---
description:  Choosing and implementing a UI for the mutator. 
---

import Image from '@site/src/components/Image';

# Build a custom mutator

## 6. Create a UI

Now that you've created, registered, and set up the mutator, it's time to 
consider how the user should add and remove inputs. 

### UI options

The best UI for your mutator is highly dependent on what the mutator does, and 
who the audience of your Blockly app is. There are a few options for your
mutator UI: 

1. Blockly default: Blockly mutators use a gear icon which opens up a mini workspace 
in which users can drag blocks to form their desired mutator shape. See the 
[mutators guide](https://docs.blockly.com/guides/create-custom-blocks/mutators/#compose-and-decompose)
for more information on how to implement the default UI. 

<Image
  src="/images/codelabs/custom-mutator/if_else_default.png"
  alt="An if-else block that uses the default mutator, with the mutator workspace open"
  width={300}
  className="codelabImage"
/>

2. Plus-minus: The [plus-minus plugin](https://raspberrypifoundation.github.io/blockly-samples/plugins/block-plus-minus/test/index.html)
adds + and - icons that the user can click to add or remove inputs.

<Image
  src="/images/codelabs/custom-mutator/if_else_plus_minus.png"
  alt="An if-else block with a plus icon beside 'if' and a minus icon beside 'else if'"
  className="codelabImage"
/>

3. Dynamic connections: The [dynamic connections plugin](https://raspberrypifoundation.github.io/blockly-samples/plugins/block-dynamic-connection/test/index.html)
automatically adds and removes inputs based on user interaction.

<Image
  src="/images/codelabs/custom-mutator/if_else_dynamic.gif"
  alt=""
  className="codelabImage"
/>

4. Custom UI: In addition to the above options, you can also implement your own 
custom ways of interacting with the mutator. 

### Custom UI with context menus

This codelab will implement a custom UI using Blockly's context menus. 

See the [context menu guide](https://docs.blockly.com/guides/configure/context-menus/) 
for general information about context menus in Blockly. For a walkthrough of 
adding custom context menu items, see the [context menu codelab](https://docs.blockly.com/codelabs/context-menu-option/codelab-overview/).

Any mutator UI option has benefits and drawbacks. Using context menus
to define mutator behavior is a helpful example to see how custom UI behavior
can work. However, options in the context menu are not very discoverable to 
users, so this approach is generally *not* recommended unless you have a 
specific reason to use context menus.

### Add callbacks

Two more functions complete the `LIST_MUTATOR` object: `addConnection()` 
and `removeConnection()`. These functions can be called to add or remove an input.
They simply update the `itemCount` and call `updateShape()` to update the block.

Add the following code to the `LIST_MUTATOR` object:

```js
export const LIST_MUTATOR = {
    ...

    addConnection: function() {
        this.itemCount++;
        this.updateShape();
    },
    removeConnection: function() {
        if (this.itemCount > 1) {
            this.itemCount--;
            this.updateShape();
        }
    },
};
```

### Create the "Add Item" context menu option

First, create the context menu option that adds an input to the list. For the 
precondition, check if this is the right type of block. This will determine 
whether the "Add Item" option should be enabled or hidden.

Since the mutator is "mixed in" to the block definition, you can call 
`addConnection()` directly on the block for the callback function. 

Add the following code to `index.js`:

```js
function registerAddItem() {
  const addItem = {
    displayText: 'Add Item',
    preconditionFn: function (scope) {
      if (
        scope.focusedNode instanceof Blockly.BlockSvg && 
        !scope.focusedNode.isInFlyout &&
        scope.focusedNode.type === 'resizable_list'
      ) {
        return 'enabled';
      }
      return 'hidden';
    }, 
    callback: (scope) => { scope.focusedNode.addConnection(); },
    id: 'add_item',
    weight: 100,
  };
  Blockly.ContextMenuRegistry.registry.register(addItem);
}
```

### Create the "Remove Item" context menu option

The "Remove Item" option is largely the same as the "Add Item" option. However, 
it also includes a guard to ensure that the total number of items will not be 
less than one. If there is only one input, the "Remove Item" option will be
greyed out:

<Image
  src="/images/codelabs/custom-mutator/greyed_out_context_option.png"
  alt="Custom list block with one input and an open context menu that shows a greyed out 'Remove Item' option"
  width={300}
  className="codelabImage"
/>

Add the following code to `index.js`:

```js
function registerRemoveItem() {
  const removeItem = {
    displayText: 'Remove Item',
    preconditionFn: function (scope) {
      if (
        scope.focusedNode instanceof Blockly.BlockSvg && 
        !scope.focusedNode.isInFlyout &&
        scope.focusedNode.type === 'resizable_list'
      ) {
        if(scope.focusedNode.itemCount <= 1) {
          return 'disabled';
        }
        return 'enabled';
      }
      return 'hidden';
    }, 
    callback: (scope) => { scope.focusedNode.removeConnection(); },
    id: 'remove_item',
    weight: 110,
  };
  Blockly.ContextMenuRegistry.registry.register(removeItem);
}
```

### Call the register functions

Finally, call both `registerAddItem()` and `registerRemoveItem()` in `index.js`,  
just after the block and mutator registrations:

```js {}
registerAddItem();
registerRemoveItem();
```

---

### Packages Docs Docs Codelabs Custom Mutator Event Handling (`packages/docs/docs/codelabs/custom-mutator/event-handling.mdx`)

---
description: Adding event firing and event groups to the mutator. 
---

# Build a custom mutator

## 8. Add event handling

Currently, the code window of the app does not update when an input is added or 
removed. 

The best way to fix this issue is to fire an event when the block is mutated. 
There are many [Blockly event options](https://docs.blockly.com/reference/namespaces/Events/#classes) 
to choose from. In this scenario, [`BlockChange`](https://docs.blockly.com/reference/namespaces/Events/classes/BlockChange/) 
is the best choice.

### Add a wrapper function 

Since `updateShape()` is called from `loadExtraState()`, it is not the ideal 
location for your new event. Adding the event to `updateShape()` would mean that 
a `BlockChange` event is (incorrectly) fired every time the workspace is loaded. 

Instead, build a wrapper function to update the `itemCount`, the shape, and fire
an event when necessary. Add the following function to the 
`LIST_MUTATOR` object.

```js
setItemCount: function(newCount) {
    // Keep track of the old state for creating the event
    const oldCountState = JSON.stringify(this.saveExtraState());

    // Update the count and shape
    this.itemCount = newCount;
    this.updateShape();

    // Keep track of the new state for creating the event
    const newCountState = JSON.stringify(this.saveExtraState());

    // If the state has changed, create and fire a BLOCK_CHANGE event
    if (newCountState !== oldCountState) {
        const BlockChangeClass = Blockly.Events.get(Blockly.Events.BLOCK_CHANGE);
        const blockChangeEvent = new BlockChangeClass(
            this,
            'mutation',
            null,
            oldCountState,
            newCountState
        );
        Blockly.Events.fire(blockChangeEvent);
    }
},
```

Note that this function keeps track of the JSON state of both the old and new 
state, so that the event can fire with information from both states.

### Update `addConnection` and `removeConnection`

Update the implementation of the `addConnection()` and `removeConnection()` 
functions in the `LIST_MUTATOR` to use the new `setItemCount()` helper:

```js
export const LIST_MUTATOR = {
    ...

    addConnection: function() {
        this.setItemCount(this.itemCount + 1);
    },
    removeConnection: function() {
        if (this.itemCount > 1) {
            this.setItemCount(this.itemCount - 1);
        }
    },

    ...
};
```

### Test it

Test the new behavior. Run `npm run start` in your app's folder or refresh the 
running app. When you add or remove connections to the list, your code window 
now should update accordingly.

However, there's still a problem. Try the following sequence:
1. Add a block to the last input in the list.
1. Remove an input.
1. Press Ctrl+z (or Cmd+z on Mac) to undo the input removal. 

You'll notice that it takes multiple undo actions to get back to the state the 
blocks were in before removing the last input.  

### Set the event group

The reason for this issue is that there are multiple events involved in removing 
an input. The mutation includes the event you fire in `setItemCount()` *and* 
other events that Blockly fires as part of the mutation process. For instance, 
after the last input is removed, the block that was attached to that input is 
moved away from the list block. This fires a `BlockMove` event.

Effectively, all of these events are part of the same process: the block 
mutation. The solution for this is grouping all of the mutation events together 
in one event group. Setting an event group at the beginning of the mutation 
means that the whole mutation will be one action in the undo/redo stream. 

Update `setItemCount()` by adding the highlighted lines of code:

```js {2,3,4,26}
setItemCount: function(newCount) {
    // If there's no event group, start one so the whole mutation is one event
    const existingGroup = Blockly.Events.getGroup();
    if (!existingGroup) Blockly.Events.setGroup(true);

    const oldCountState = JSON.stringify(this.saveExtraState());

    this.itemCount = newCount;
    this.updateShape();

    const newCountState = JSON.stringify(this.saveExtraState());

    // If the state has changed, create and fire a BLOCK_CHANGE event
    if (newCountState !== oldCountState) {
        const BlockChangeClass = Blockly.Events.get(Blockly.Events.BLOCK_CHANGE);
        const blockChangeEvent = new BlockChangeClass(
            this,
            'mutation',
            null,
            oldCountState,
            newCountState
        );
        Blockly.Events.fire(blockChangeEvent);
    }

    Blockly.Events.setGroup(existingGroup);
},
``` 

If something else outside of the mutation has already grouped this mutation into 
an event group, respect that group. In code, this means that if `getGroup()` 
returns a value, do not set a new group. 

### Test it (again)

Test the event group by running `npm run start` or refreshing the app. Follow 
the same sequence as before: 
1. Add a block to the last input in the list.
1. Remove an input.
1. Press Ctrl+z (or Cmd+z on Mac) to undo the input removal. 

The undo should now fully undo the entire action.

---

### Packages Docs Docs Codelabs Custom Mutator Setup (`packages/docs/docs/codelabs/custom-mutator/setup.mdx`)

---
description: Setting up the "Build a custom mutator" codelab.
---

import Image from '@site/src/components/Image';

# Build a custom mutator

## 2. Setup

This codelab will demonstrate how to add code to the Blockly sample app to create a custom mutator.

### The application

Use the [`npx @blockly/create-package app`](https://www.npmjs.com/package/@blockly/create-package) command to create a standalone application that contains a sample setup of Blockly, including custom blocks and a display of the generated code and output.

1. Run `npx @blockly/create-package app custom-mutator-codelab`. This will create a blockly application in the folder `custom-mutator-codelab`.
1. `cd` into the new directory: `cd custom-mutator-codelab`.
1. Run `npm start` to start the server and run the sample application.
1. The sample app will automatically run in the browser window that opens.

### Change the storage key

Before setting up the rest of the application, change the storage key used for this codelab application. This will ensure that the workspace is saved in its own storage, separate from the regular sample app, so that it doesn't interfere with other demos. 

In `serialization.js`, change the value of `storageKey` to some unique string. `customMutatorWorkspace` will work:

```js
// Use a unique storage key for this codelab
const storageKey = 'customMutatorWorkspace';
```

### Explore the starter code

Take a moment to explore the code you just created in the `custom-mutator-codelab` folder. If you'd like a more in-depth explanation of all of the code in the sample app, check out the [getting started codelab](/codelabs/getting-started/codelab-overview) which goes through creating this sample app from scratch.

For a briefer outline of the code, visit the [sample app overview](/guides/get-started/sample-app-overview/) page for an overview of the included files and tooling.

---

### Packages Docs Docs Codelabs Custom Mutator Summary (`packages/docs/docs/codelabs/custom-mutator/summary.mdx`)

---
pagination_next: null
description: Summary of the build a custom mutator codelab.
---

# Build a custom mutator

## 9. Summary

And with that, you've finished building a custom mutator!

In this codelab, you learned:
- How to create a mutator in Blockly
- How to serialize and deserialize the mutator's extra state
- What UI options exist for Blockly mutators
- How to create a custom UI for a mutator
- How to fire events during a mutation
- When and how to use event groups

## Resources

- [Mutator guides](https://docs.blockly.com/guides/create-custom-blocks/mutators/)
- [Plus-minus plugin demo](https://raspberrypifoundation.github.io/blockly-samples/plugins/block-plus-minus/test/index.html)
- [Dynamic connections plugin demo](https://raspberrypifoundation.github.io/blockly-samples/plugins/block-dynamic-connection/test/index.html)

If you're implementing a custom mutator UI, it may also be useful to view the 
source code for the [plus-minus plugin](https://github.com/RaspberryPiFoundation/blockly/tree/main/packages/plugins/block-plus-minus)
and the [dynamic connections plugin](https://github.com/RaspberryPiFoundation/blockly/tree/main/packages/plugins/block-dynamic-connection).

---

### Packages Docs Docs Codelabs Custom Mutator The Basics (`packages/docs/docs/codelabs/custom-mutator/the-basics.mdx`)

---
description:  What a mutator is, and setup of the custom block. 
---

import Image from '@site/src/components/Image';

# Build a custom mutator

## 3. Mutator overview and block creation

When a block has extra state that can't be captured by its fields, it needs a 
mutator. Common examples are if/else and list blocks, which need to keep 
track of how many inputs they have.

Mutators are a type of [mixin](https://docs.blockly.com/guides/create-custom-blocks/define/extensions/#mixins),
meaning that they add custom functions to a block. The functions that a mutator 
includes depends on the desired behavior of the mutator. At the very least, 
mutators all need [serialization hooks](https://docs.blockly.com/guides/create-custom-blocks/mutators/#serialization-hooks) 
in order to save and load the extra state. This codelab uses a custom mutator UI, 
but mutators that implement the default UI must also include `compose` and 
`decompose` functions. For more on mutators and the default mutator UI, visit 
the [mutators guide](https://docs.blockly.com/guides/create-custom-blocks/mutators/).

In this codelab, you will be making a custom list block mutator. This starts with 
creating the block.

### Create the custom block 

In the `blocks` folder, create a new file called `list.js`. Add the following
code to create the custom block definition:

```js
import * as Blockly from 'blockly/core';

const resizableListBlock = {
  type: 'resizable_list',
  message0: 'resizable list with %1',
  args0: [
    {
      type: 'input_value',
      name: 'ADD0',
    }
  ],
  output: null,
  style: "list_blocks",
  tooltip: '',
  helpUrl: '',
};

// Create the block definitions
export const mutatorBlocks = Blockly.common.createBlockDefinitionsFromJsonArray(
  [resizableListBlock]
);
```

For more on block definitions, review the [block definition guides](https://docs.blockly.com/guides/create-custom-blocks/define/block-definitions/).

### Use the new block

Now, register the new block and add it to the toolbox in order to use it in the 
workspace. In `index.js`, import the block definition, then register the block where the other
custom block and generator are registered:

```js {1,7}
import {mutatorBlocks} from './blocks/list'; // Add this import to index.js

...

// Register the blocks and generator with Blockly
Blockly.common.defineBlocks(blocks);
Blockly.common.defineBlocks(mutatorBlocks); // Add this line to index.js
Object.assign(javascriptGenerator.forBlock, forBlock);
```

The toolbox should also contain the new block, so that it can be dragged into 
the workspace and used. Find the 'Lists' category in `toolbox.js`, then add an 
entry for the new block:

```js {6-9}
{
    kind: 'category',
    name: 'Lists',
    categorystyle: 'list_category',
    contents: [
    {
        kind: 'block', 
        type: 'resizable_list', 
    },
    {
        kind: 'block',
        type: 'lists_create_with',
    },
    ...
}
```

### Add a stand-in generator

If you start the app now by running `npm run start` in the codelab folder, then
attempt to drag the new block into the workspace, you'll likely get an error:
`JavaScript generator does not know how to generate code for block type "resizable_list".`

This error occurs because sample app's code window displays the code for all 
blocks on the workspace, but this new block does not yet have a 
[block-code generator](https://docs.blockly.com/guides/create-custom-blocks/code-generation/block-code/). 
Without the block-code generator, Blockly's JavaScript generator can't generate 
the code for the new block.

For now, insert a placeholder generator to avoid this error. After you add the 
mutator functions in the next few steps, you will circle back and implement this 
generator code. 

Add the following code to `javascript.js`, which is in the `generators` folder:

```js
forBlock['resizable_list'] = function (block, generator) {
    // `resizable_list` has an output, so its generator must return a [code, order] tuple
    return ['', Order.ATOMIC];
}
```

### Test it

Start the app by first navigating to the codelab folder in the terminal, then 
run `npm run start`. Open the list category to see the new block. It now can be 
dragged into the workspace, but there is not a way to add or remove inputs yet. 

<Image
  src="/images/codelabs/custom-mutator/block_in_flyout.png"
  alt="The new list block seen in the 'List' category of the toolbox flyout"
  className="codelabImage"
/>

---

### Packages Docs Docs Codelabs Custom Mutator Update Shape (`packages/docs/docs/codelabs/custom-mutator/update-shape.mdx`)

---
description: How to update the shape of a mutator block.
---

import Image from '@site/src/components/Image';

# Build a custom mutator

## 5. Update the block shape

The `resizable_list` needs to add or remove inputs depending on the number 
of items in the list. This means that the shape of the block should be updated 
based on the `itemCount`. 

A block with `itemCount==1` should have just one input:
<Image
  src="/images/codelabs/custom-mutator/list_block_one_input.png"
  alt="A list block with one input"
  className="codelabImage"
/>

A block with `itemCount==2` should have two inputs:
<Image
  src="/images/codelabs/custom-mutator/list_block_two_inputs.png"
  alt="A list block with two inputs"
  className="codelabImage"
/>

And so on. The block implemented in this codelab will always have a minimum of 
one input. 

Note that blocks with mutators don't always *need* to change their shape based 
on the extra state. In this case, updating the shape is necessary.

### Adding an input

The same `updateShape()` function will be responsible for updating the shape
regardless of whether an input has been added or removed. First, focus on adding
a new input. Add the following function and code to the `LIST_MUTATOR`:

```js
export const LIST_MUTATOR = { 
    ... 

    updateShape: function() {
        // Add new inputs.
        for (let i = 1; i < this.itemCount; i++) {
            if (!this.getInput('ADD' + i)) {
                this.appendValueInput('ADD' + i).setAriaLabelProvider(
                    () => 'value ' + (i + 1)
                );
            }
        }
    },
};
```

The `updateShape()` function adds `itemCount - 1` inputs, since the block
starts with 1 input. This function also sets the aria label for each input 
manually, so that screenreaders distinguish clearly between each input. 

Finally, note that the inputs are named numerically. The input that you defined 
in the block definition is called `ADD0`, so subsequent blocks are named `ADD1`, 
`ADD2`, `ADD3`, etc.

### Removing an input

To remove an input, remove the appropriate number of inputs from the end of the 
list. Finish the `updateShape()` function with the code below: 

```js
export const LIST_MUTATOR = { 
    ... 

    updateShape: function() {
        // Add new inputs.
        for (let i = 1; i < this.itemCount; i++) {
            if (!this.getInput('ADD' + i)) {
                this.appendValueInput('ADD' + i).setAriaLabelProvider(
                    () => 'value ' + (i + 1)
                );
            }
        }
        // Remove deleted inputs.
        for (let i = this.itemCount; this.getInput('ADD' + i); i++) {
            this.removeInput('ADD' + i);
        }
    },
};
```

### Updating after load 
Since this list block will add or remove inputs based on the value of 
`itemCount`, it is important to update the physical shape after deserialization. 
Add a call to `updateShape()` in `loadExtraState()`:

```js {3}
loadExtraState: function(state) {
    this.itemCount = state['itemCount'];
    this.updateShape();
},
```

### Next steps

Although `updateShape()` is complete, only the deserializer calls it. The next 
step of creating a mutator is considering how the user will interact with the 
mutator in order to modify the `extraState`.

---

### Packages Docs Docs Codelabs Custom Renderer Change Connection Shapes (`packages/docs/docs/codelabs/custom-renderer/change-connection-shapes.mdx`)

---
description: How to change connection shapes.
---

# Build custom renderers

## 7. Change connection shapes

This step will define and use new shapes for previous/next connections and input/output connections. This takes three steps:

1. Define new shape objects.
1. Override `init()` to store the new shape objects.
1. Override `shapeFor(connection)` to return the new objects.

### Define a previous/next connection shape

An outline path is drawn clockwise around the block, starting at the top left. As a result the previous connection is drawn from left-to-right, while the next connection is drawn from right-to-left.

Previous and next connections are defined by the same object. The object has four properties:

- `width`: The width of the connection.
- `height`: The height of the connection.
- `pathLeft`: The sub-path that describes the connection when drawn from left-to-right.
- `pathRight`: The sub-path that describes the connection when drawn from right-to-left.

Define a new function called `makeRectangularPreviousConn()` and put it inside the `CustomConstantProvider` class definition. Note that `NOTCH_WIDTH` and `NOTCH_HEIGHT` have already been overridden in the `constructor()`, so they'll be reused:

```js
  /**
   * @returns Rectangular notch for use with previous and next connections.
   */
  makeRectangularPreviousConn() {
    const width = this.NOTCH_WIDTH;
    const height = this.NOTCH_HEIGHT;

    /**
     * Since previous and next connections share the same shape you can define
     * a function to generate the path for both.
     *
     * @param dir Multiplier for the horizontal direction of the path (-1 or 1)
     * @returns SVGPath line for use with previous and next connections.
     */
    function makeMainPath(dir) {
      return Blockly.utils.svgPaths.line(
          [
            Blockly.utils.svgPaths.point(0, height),
            Blockly.utils.svgPaths.point(dir * width, 0),
            Blockly.utils.svgPaths.point(0, -height),
          ]);
    }
    const pathLeft = makeMainPath(1);
    const pathRight = makeMainPath(-1);

    return {
      width: width,
      height: height,
      pathLeft: pathLeft,
      pathRight: pathRight,
    };
  }
```

### Define an input/output connection shape

Just as previous/next connection shapes are drawn from left-to-right and right-to-left, input/output connection shapes are drawn from top-to-bottom and bottom-to-top.

Input and output connections are defined by the same object. The object has four properties:

- `width`: The width of the connection.
- `height`: The height of the connection.
- `pathUp`: The sub-path that describes the connection when drawn from top-to-bottom.
- `pathDown`: The sub-path that describes the connection when drawn from bottom-to-top.

Define a new function called `makeRectangularInputConn()` and put it inside the `CustomConstantProvider` class definition. Note that `TAB_WIDTH` and `TAB_HEIGHT` have already been overridden in the `constructor()` so they'll be reused:

```js
  /**
   * @returns Rectangular puzzle tab for use with input and output connections.
   */
  makeRectangularInputConn() {
    const width = this.TAB_WIDTH;
    const height = this.TAB_HEIGHT;

    /**
     * Since input and output connections share the same shape you can define
     * a function to generate the path for both.
     *
     * @param dir Multiplier for the vertical direction of the path (-1 or 1)
     * @returns SVGPath line for use with input and output connections.
     */
    function makeMainPath(dir) {
      return Blockly.utils.svgPaths.line(
          [
            Blockly.utils.svgPaths.point(-width, 0),
            Blockly.utils.svgPaths.point(0, dir * height),
            Blockly.utils.svgPaths.point(width, 0),
          ]);
    }
    const pathUp = makeMainPath(-1);
    const pathDown = makeMainPath(1);

    return {
      width: width,
      height: height,
      pathUp: pathUp,
      pathDown: pathDown,
    };
  }
```

### Override init()

Override the `init()` function in the `CustomConstantProvider` class definition and store the new shape objects as `RECT_PREV_NEXT` and `RECT_INPUT_OUTPUT`. Make sure to call the superclass `init()` function to store other objects that have not been overridden.

```js
  /**
   * @override
   */
  init() {
    // First, call init() in the base provider to store the default objects.
    super.init();

    // Add calls to create shape objects for the new connection shapes.
    this.RECT_PREV_NEXT = this.makeRectangularPreviousConn();
    this.RECT_INPUT_OUTPUT = this.makeRectangularInputConn();
  }
```

### Override shapeFor(connection)

Next, override the `shapeFor(connection)` function in the `CustomConstantProvider` class definition and return the new custom objects:

```js
  /**
   * @override
   */
  shapeFor(connection) {
    switch (connection.type) {
      case Blockly.INPUT_VALUE:
      case Blockly.OUTPUT_VALUE:
        return this.RECT_INPUT_OUTPUT;
      case Blockly.PREVIOUS_STATEMENT:
      case Blockly.NEXT_STATEMENT:
        return this.RECT_PREV_NEXT;
      default:
        throw Error('Unknown connection type');
    }
  }
```

### The result

Return to the browser, click on the `Loops` entry, and drag out a repeat block. The resulting block should have rectangular connections for all four connection types.

---

### Packages Docs Docs Codelabs Custom Renderer Define And Register A Custom Renderer (`packages/docs/docs/codelabs/custom-renderer/define-and-register-a-custom-renderer.mdx`)

---
description: How to register a custom renderer.
---

# Build custom renderers

## 4. Define and register a custom renderer

A **Renderer** is the interface between custom rendering code and the rest of Blockly. Blockly provides a base renderer with all required fields already set to usable values.

To start, create a new directory at `src/renderers` and add a file inside named `custom.js`.

At the top of the file, import `blockly/core`:

```js
import * as Blockly from 'blockly/core';
```

Then define a new custom renderer and have it extend the base renderer:

```js
class CustomRenderer extends Blockly.blockRendering.Renderer {
  constructor() {
    super();
  }
}
```

After defining the renderer, register it with Blockly and give it the name `custom_renderer`:

```js
Blockly.blockRendering.register('custom_renderer', CustomRenderer);
```

To use the custom renderer, import the new file at the top of `src/index.js`:

```js
import './renderers/custom';
```

Now, add the the `renderer` property into the configuration struct passed to `Blockly.inject` so that it now looks like this:

```js
const ws = Blockly.inject(blocklyDiv, {
  renderer: 'custom_renderer',
  toolbox,
});
```

### The result

If the server is already running, refresh the page to see the new changes. Otherwise, run `npm start` to start the server. Once the server is running, click on the `Loops` entry in the browser and drag out a repeat block. The resulting block will use the same values already defined in the base `Blockly.blockRendering.Renderer`.

---

### Packages Docs Docs Codelabs Custom Renderer Observe The Built In Renderers (`packages/docs/docs/codelabs/custom-renderer/observe-the-built-in-renderers.mdx`)

---
description: Introduction to the built-in renderers.
---

# Build custom renderers

## 3. Observe the built-in renderers

First, visit [the advanced playground](https://raspberrypifoundation.github.io/blockly/packages/blockly/tests/playgrounds/advanced_playground.html) to observe what the built-in renderers look like.

Click on the "Loops" entry and drag out a repeat block. Now, change the selection in the "renderer" drop down to observe the look of each built-in renderer. By default, the renderer named "Thrasos" is used.

---

### Packages Docs Docs Codelabs Custom Renderer Override Constants (`packages/docs/docs/codelabs/custom-renderer/override-constants.mdx`)

---
description: How to override the constants in a renderer.
---

# Build custom renderers

## 5. Override constants

A **ConstantsProvider** holds all rendering-related constants. This includes sizing information and colours. Blockly provides a base **ConstantsProvider** with all required fields set to default values.

The **ConstantsProvider** `constructor()` sets all static properties, such as `NOTCH_WIDTH` and `NOTCH_HEIGHT`. For a full list of properties, see [constants.ts](https://github.com/RaspberryPiFoundation/blockly/blob/main/packages/blockly/core/renderers/common/constants.ts).

Only override the necessary subset of the constants, rather than all of them. To do so:

- Define a constants provider that extends the base `ConstantProvider`.
- Call the superclass `super()` in the `constructor()`.
- Set individual properties.

Add this above the `CustomRenderer` definition in `src/renderers/custom.js`:

```js
class CustomConstantProvider extends Blockly.blockRendering.ConstantProvider {
  constructor() {
    // Set up all of the constants from the base provider.
    super();

    // Override a few properties.
    /**
     * The width of the notch used for previous and next connections.
     * @type {number}
     * @override
     */
    this.NOTCH_WIDTH = 20;

    /**
     * The height of the notch used for previous and next connections.
     * @type {number}
     * @override
     */
    this.NOTCH_HEIGHT = 10;

    /**
     * Rounded corner radius.
     * @type {number}
     * @override
     */
    this.CORNER_RADIUS = 2;

    /**
     * The height of the puzzle tab used for input and output connections.
     * @type {number}
     * @override
     */
    this.TAB_HEIGHT = 8;
  }
}
```

To use the new **CustomConstantProvider**, override `makeConstants_()` inside the `CustomRenderer` class. Below the `constructor()`, add:

```js
  /**
   * @override
   */
  makeConstants_() {
    return new CustomConstantProvider();
  }
```

### The result

Return to the browser, click on the `Loops` entry, and drag out a repeat block. The resulting block should have triangular previous and next connections, and skinny input and output connections. Note that the general shapes of the connections have not changed--only parameters such as width and height.

---

### Packages Docs Docs Codelabs Custom Renderer Setup (`packages/docs/docs/codelabs/custom-renderer/setup.mdx`)

---
description: Setting up the "Build custom renderers" codelab.
---

# Build custom renderers

## 2. Setup

This codelab will add code to the Blockly sample app to create and use a new custom renderer.

### The application

Use the [`npx @blockly/create-package`](https://www.npmjs.com/package/@blockly/create-package) command to create a standalone application that contains a sample setup of Blockly, including custom blocks and a display of the generated code and output.

1. Run `npx @blockly/create-package app custom-renderer-codelab`. This will create a blockly application in the folder `custom-renderer-codelab`.
1. `cd` into the new directory: `cd custom-renderer-codelab`.
1. Run `npm start` to start the server and run the sample application.
1. The sample app will automatically run in the browser window that opens.

The initial application uses the default renderer and contains no code or definitions for a custom renderer.

### Change the storage key

Before setting up the rest of the application, change the storage key used for this codelab application. This will ensure that the workspace is saved in its own storage, separate from the regular sample app, so that it doesn't interfere with other demos. 

In `serialization.js`, change the value of `storageKey` to some unique string. `customRenderersWorkspace` will work:

```js
// Use a unique storage key for this codelab
const storageKey = 'customRendererWorkspace';
```

### Explore the starter code

Take a moment to explore the code you just created in the `custom-renderer-codelab` folder. If you'd like a more in-depth explanation of all of the code in the sample app, check out the [getting started codelab](/codelabs/getting-started/codelab-overview) which goes through creating this sample app from scratch.

For a briefer outline of the code, visit the [sample app overview](/guides/get-started/sample-app-overview/) page for an overview of the included files and tooling.

---

### Packages Docs Docs Codelabs Custom Renderer Summary (`packages/docs/docs/codelabs/custom-renderer/summary.mdx`)

---
pagination_next: null
description: Summary of the "Build custom renderers" codelab.
---

# Build custom renderers

## 9. Summary

Custom renderers are a powerful way to change the look and feel of Blockly. In this codelab you learned:

- How to declare and register a custom renderer by extending `Blockly.blockRendering.Renderer`.
- How to override renderer constants such as `NOTCH_HEIGHT` in `Blockly.blockRendering.ConstantProvider`.
- How to modify connection shapes by creating custom [SVG paths](https://developer.mozilla.org/en-US/docs/Web/SVG/Element/path), storing them in `init()`, and finally returning them in `shapeFor(connection)`.
- How to update the mapping from connection to connection shape by adding logic in `shapeFor(connection)`.

---

### Packages Docs Docs Codelabs Custom Renderer Typed Connection Shapes (`packages/docs/docs/codelabs/custom-renderer/typed-connection-shapes.mdx`)

---
description: How to set connection shapes based on connection types.
---

# Build custom renderers

## 8. Typed connection shapes

This step will change the custom renderer so that it sets connection shapes at runtime based on a connection's type checks. It will use the default connection shapes and the shapes defined in the previous steps.

### Override `shapeFor(connection)`

Override the `shapeFor(connection)` function in the `CustomConstantProvider` class definition to return a different connection shape based on the `checks` returned from `connection.getCheck()`. Note the previous definition of `shapeFor(connection)` created in previous steps will need to be deleted.

The new definition of `shapeFor(connection)` will:

- Return a rectangular tab for inputs and outputs that accept `Number`s and `String`s.
- Return the default puzzle tab for all other inputs and outputs.
- Return the normal notch for all previous and next connections.

```js
/**
 * @override
 */
shapeFor(connection) {
  var checks = connection.getCheck();
  switch (connection.type) {
    case Blockly.INPUT_VALUE:
    case Blockly.OUTPUT_VALUE:
      if (checks && checks.includes('Number')) {
        return this.RECT_INPUT_OUTPUT;
      }
      if (checks && checks.includes('String')) {
        return this.RECT_INPUT_OUTPUT;
      }
      return this.PUZZLE_TAB;
    case Blockly.PREVIOUS_STATEMENT:
    case Blockly.NEXT_STATEMENT:
      return this.NOTCH;
    default:
      throw Error('Unknown connection type');
  }
```

### The result

Take these steps to fully test this change in the browser:

1. Click on the `Loops` entry and drag out a repeat block.
1. Click on the `Logic` entry and drag the conditional `if` block into the repeat block that was placed on the workspace in the previous step.

There should be an entry similar to the screenshot below, in which the `Number` inputs and outputs are rectangular, but the boolean input on the `if` block is a puzzle tab.

---

### Packages Docs Docs Codelabs Custom Renderer Understand Connection Shapes (`packages/docs/docs/codelabs/custom-renderer/understand-connection-shapes.mdx`)

---
description: Introduction to connection shapes.
---

# Build custom renderers

## 6. Understand connection shapes

A common use case of a custom renderer is changing the shape of connections. This requires a more detailed understanding of how a block is drawn and how SVG paths are defined.

### The block outline

The outline of the block is a single [SVG path](https://developer.mozilla.org/en-US/docs/Web/SVG/Element/path). The outline is built out of many sub-paths (e.g. the path for a previous connection; the path for the top of the block; and the path for an input connection).

Each sub-path is a string of [path commands](https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/d#path_commands) that describe the appropriate shape. These commands must use relative (rather than absolute) coordinates.

SVG path commands can be written as strings, but Blockly provides a set of [utility functions](/reference/namespaces/utils/namespaces/svgPaths) to make writing and reading paths easier.

### `init()`

A connection's shape is stored as an object with information about its width, height, and sub-path. These objects are created in the `ConstantProvider`s `init()` function. Here is the start of the default implementation. The complete definition can be found inside [`constants.ts`](https://github.com/RaspberryPiFoundation/blockly/blob/main/packages/blockly/core/renderers/common/constants.ts).

```js
/**
 * Initialize shape objects based on the constants set in the constructor.
 */
init() {
  /**
   * An object containing sizing and path information about collapsed block
   * indicators.
   */
  this.JAGGED_TEETH = this.makeJaggedTeeth();

  /** An object containing sizing and path information about notches. */
  this.NOTCH = this.makeNotch();

  // Additional code has been removed for brevity.
}
```

**Properties that are primitives should be set in the `constructor()`, while objects should be set in `init()`**. This separation allows a subclass to override a constant such as `NOTCH_WIDTH` and see the change reflected in objects that depend on the constant.

### `shapeFor(connection)`

The `shapeFor(connection)` function maps from connection to connection shape. Here is the default implementation, which can be found inside [`constants.ts`](https://github.com/RaspberryPiFoundation/blockly/blob/main/packages/blockly/core/renderers/common/constants.ts). It returns a puzzle tab for input/output connections and a notch for previous/next connections:

```js
/**
 * Get an object with connection shape and sizing information based on the
 * type of the connection.
 *
 * @param connection The connection to find a shape object for
 * @returns The shape object for the connection.
 */
shapeFor(connection: RenderedConnection): Shape {
  switch (connection.type) {
    case ConnectionType.INPUT_VALUE:
    case ConnectionType.OUTPUT_VALUE:
      return this.PUZZLE_TAB;
    case ConnectionType.PREVIOUS_STATEMENT:
    case ConnectionType.NEXT_STATEMENT:
      return this.NOTCH;
    default:
      throw Error('Unknown connection type');
  }
}
```

---

### Packages Docs Docs Codelabs Custom Toolbox Add A Custom Category (`packages/docs/docs/codelabs/custom-toolbox/add-a-custom-category.mdx`)

---
description: How to create a custom category.
---

import Image from '@site/src/components/Image';

# Customizing a Blockly toolbox

## 3. Make a custom category

### Define and register a custom category

To start, create a file named `custom_category.js` in the `src` directory.  

In order to create a custom category, you will create a new category that extends
the default `Blockly.ToolboxCategory` class. Add a Blockly import and class definition to your `custom_category.js` file:

```js
import * as Blockly from 'blockly';

class CustomCategory extends Blockly.ToolboxCategory {
  // You'll add functions to this class in the next step

}
```

After defining your category you need to tell Blockly that it exists.
Create a function to register your category by adding the below code to the end of `custom_category.js`:

```js
export function registerCustomCategory() {
  Blockly.registry.register(
    Blockly.registry.Type.TOOLBOX_ITEM,
    Blockly.ToolboxCategory.registrationName,
    CustomCategory,
    true,
  );
}
```

Finally, you'll need to import the registration function in `index.js`.
To register the custom category, call the `registerCustomCategory()` function in `index.js`, just after registering the blocks and generator:

```js
import { registerCustomCategory } from './custom_category.js';

// Register the blocks and generator with Blockly
Blockly.common.defineBlocks(blocks);
Object.assign(javascriptGenerator.forBlock, forBlock);

// Register the custom category
registerCustomCategory();
```

By registering our `CustomCategory` with `Blockly.ToolboxCategory.registrationName`
we are *overriding* the default category in Blockly. Because we are overriding a
toolbox item instead of adding a new one, we must pass in `true` as the last
argument. If this flag is `false`, `Blockly.registry.register` will throw
an error because we are overriding an existing class.

### The result

To test, save your files, then find the browser page that has the sample app. 
You may also need to refresh the page. Your toolbox should look the same as it did before.

<Image
  src="/images/codelabs/custom-toolbox/base_toolbox.png"
  alt="The default toolbox. A list of categories with a strip of a different colour to the left of each category."
  className="codelabImage"
/>

However, if you run the below commands in your console you will see that
your toolbox is now using the `CustomCategory` class.

```js
var toolbox = Blockly.common.getMainWorkspace().getToolbox();
toolbox.getToolboxItems()[0];
```

Although nothing has visually changed yet, this codelab will use the `CustomCategory` class
to change the appearance of the categories.

---

### Packages Docs Docs Codelabs Custom Toolbox Add An Icon To Your Category (`packages/docs/docs/codelabs/custom-toolbox/add-an-icon-to-your-category.mdx`)

---
description: How to add an icon to your category.
---

import Image from '@site/src/components/Image';

# Customizing a Blockly toolbox

## 6. Add an icon to your category

We are going to add an icon to our "Logic" category by adding an icon library to
our `index.html` file, and setting the appropriate CSS class on our category definition.

To start, we are going to grab an icon library and paste it to `index.html`, inside 
the `<head>` element:

```html
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css">
```

We are going to add a cog icon from this library to the "Logic" category.
To do this, we will add the appropriate CSS classes to our category definition.
For a JSON toolbox definition like the one in `toolbox.js`, you'll use a `cssconfig` object. 

In `toolbox.js` scroll in to your toolbox definition and change the category with
the name "Logic":

```js
{
  kind: 'category',
  name: 'Logic',
  categorystyle: 'logic_category',
  contents: [ /* ...existing blocks ... */ ],
},
```

to be:

```js
{
  kind: 'category',
  name: 'Logic',
  categorystyle: 'logic_category',
  cssconfig: { icon: 'customIcon fa fa-cog' },
  contents: [ /* ...existing blocks... */ ],
},
```

All the classes used to create a category can be set similar to how we set the
icon class above. See the [Blockly toolbox documentation](/guides/configure/toolboxes/appearance#category-css) for more information.

### Add some CSS

If you open the running app you will notice that the gear icon is positioned
incorrectly and is a bit difficult to see. We will use the `customIcon` class to
change the color of the icon and use the `blocklyTreeRowContentContainer` class
to position the icon above the text.

In your `toolbox_style.css` file add:

```css
/* Changes color of the icon to white. */
.customIcon {
  color: white;
}
/* Stacks the icon on top of the label. */
.blocklyTreeRowContentContainer {
  display: flex;
  flex-direction: column;
  align-items: center;
}
.blocklyToolboxCategory {
  height: initial;
}
```

### Update setSelected

If you open the running app and click on the "Logic" category you will notice
that the white icon now blends into the white background.

In order to fix this, we are going to update our `setSelected` method to set the
color of the icon to the category color when the category has been selected.

Inside `custom_category.js` add the below line to `setSelected` if the category
has been selected:

```js
this.iconDom_.style.color = this.colour_;
```

Add the below line to `setSelected` if the category has not been selected:

```js
this.iconDom_.style.color = 'white';
```

Your `setSelected` method should look similar to below:

```js
  /** @override */
  setSelected(isSelected){
    super.setSelected(isSelected);

     // We do not store the label span on the category, so use getElementsByClassName.
     var labelDom = this.rowDiv_.getElementsByClassName('blocklyToolboxCategoryLabel')[0];
     if (isSelected) {
       // Change the background color of the div to white.
       this.rowDiv_.style.backgroundColor = 'white';
       // Set the colour of the text to the colour of the category.
       labelDom.style.color = this.colour_;
       this.iconDom_.style.color = this.colour_;
     } else {
       // Set the background back to the original colour.
       this.rowDiv_.style.backgroundColor = this.colour_;
       // Set the text back to white.
       labelDom.style.color = 'white';
       this.iconDom_.style.color = 'white';
     }
  }
```

### The result

If you open the running app, you should see a white gear above your "Logic"
label, and it should change to blue when the category has been selected.

<Image
  src="/images/codelabs/custom-toolbox/category_gear.png"
  alt='A white gear above the word "Logic" on a blue background.'
  className="codelabImage"
/>

<Image
  src="/images/codelabs/custom-toolbox/category_gear_selected.png"
  alt='A blue gear above the word "Logic" on a white background.'
  className="codelabImage"
/>

---

### Packages Docs Docs Codelabs Custom Toolbox Adding A Custom Toolbox Item (`packages/docs/docs/codelabs/custom-toolbox/adding-a-custom-toolbox-item.mdx`)

---
description: How to add a custom item to a toolbox.
---

import Image from '@site/src/components/Image';

# Customizing a Blockly toolbox

## 8. Adding a custom toolbox item

In the previous sections we modified the toolbox by extending the base category class.
In this section we will make a completely new toolbox item and add it to our toolbox.

For this example, we are going to create a toolbox label.

### Setup

In the same directory as `index.js` create a new file named `toolbox_label.js`.
Create a class in `toolbox_label.js` that extends `Blockly.ToolboxItem` and create a function to register it.

```js
import * as Blockly from 'blockly';

class ToolboxLabel extends Blockly.ToolboxItem {
  // You'll add functions to this class soon

}

export function registerToolboxLabel() {
  Blockly.registry.register(
    Blockly.registry.Type.TOOLBOX_ITEM,
    'toolboxlabel',
    ToolboxLabel,
  );
}
```

As with the custom category, you'll also need to import the registration function in `index.js`.
To register the toolbox label, call the `registerToolboxLabel()` function in `index.js`, just after registering the custom category:

```js
import { registerToolboxLabel } from './toolbox_label.js';

...

// Register the custom category
registerCustomCategory();
// Register the toolbox label
registerToolboxLabel();
```
By registering this toolbox item with the name "toolboxlabel" we can now use this
name in our toolbox definition to add our custom item to the toolbox.

Navigate to `toolbox.js`, and add a `toolboxlabel` as the first item in the list 
of toolbox contents:

```js
{
  kind: 'toolboxlabel',
}
```

Your toolbox definition should now look something like:

```js
export const toolbox = {
  kind: 'categoryToolbox',
  contents: [
    {
      kind: 'toolboxlabel',
    },
    { kind: 'category', name: 'Logic', /* etc */ },
  // ...
  ]
}
```

### Initialize the toolbox item

In order to create a toolbox item we must implement one of the toolbox item interfaces.

For this example, we will be implementing the basic `IToolboxItem` interface.
There are three different types of toolbox item interfaces:
`IToolboxItem`, `ISelectableToolboxItem` and `ICollapsibleToolboxItem`.
Since we do not need our label to be selectable or collapsible, we can implement
the basic `IToolboxItem` interface.

First, we are going to add an init method to the `ToolboxLabel` class that will create the dom for our toolbox label:

```js
  /** @override */
  init() {
    // Create the label.
    this.label = document.createElement('label');
    // Set ARIA role and description, so that screenreaders can see and read the label
    Blockly.utils.aria.setRole(this.label, Blockly.utils.aria.Role.TREEITEM);
    Blockly.utils.aria.setState(
      this.label,
      Blockly.utils.aria.State.ROLEDESCRIPTION,
      'Label',
    );
    // Set the name.
    this.label.textContent = 'Label';
  }
```

The `init()` function defined above includes setting the ARIA role and state for 
screenreader support. To learn more, see the [screenreader support doc].(/guides/configure/screen-reader/)

Next, we are going to return this element:

```js
  /** @override */
  getDiv() {
    return this.label;
  }
```

If you refresh the app page you should see a label above your first category.

<Image
  src="/images/codelabs/custom-toolbox/toolbox_label.png"
  alt='The toolbox with a label at the top that says "Label."'
  className="codelabImage"
/>

### Add attributes to the toolbox definition

The above code is rather limiting since it only allows us to create a toolbox
label with the text "Label".
To make it possible to create different labels with different text and colour we
are going to add `name` and `colour` attributes to our toolbox definition.

Open `toolbox.js`. Add a `name` and `colour` to your toolbox label

```js
contents: [
  {
    kind: 'toolboxlabel',
    name: 'Custom Toolbox',
    colour: 'darkslategrey',
  },
  { kind: 'category', name: 'Logic', /* etc */ },
  // ...
]
```

These values will get passed in to our `ToolboxLabel` class through the `toolboxItemDef`.
Navigate to `toolbox_label.js` and add the following lines to your `init` method:

```js
// Set the name.
this.label.textContent = this.toolboxItemDef_['name'];
// Set the color.
this.label.style.color = this.toolboxItemDef_['colour'];
```

Remove the following line from your init method:

```js
this.label.textContent = 'Label';
```

All attributes on our toolbox definition get added to the `toolboxItemDef_`.
`this.toolboxItemDef_` is set in the `Blockly.ToolboxItem` constructor.

Refresh your app in a browser to see the updated label.

<Image
  src="/images/codelabs/custom-toolbox/custom_label.png"
  alt='The toolbox with a label that now says "Custom Toolbox".'
  className="codelabImage"
/>

### Add some CSS

Similar to how we added `colour` and `name` above, we are going to add a custom
class to our label.

Navigate to your toolbox definition in `toolbox.js` and add the `cssconfig`.

```js
contents: [
  {
    kind: 'toolboxlabel',
    name: 'Custom Toolbox',
    colour: 'darkslategrey',
    cssconfig: { label: 'customLabel' },
  },
  { kind: 'category', name: 'Logic', /* etc */ },
  // ...
]
```

This gets added to a `cssconfig` object stored on the `toolboxItemDef`.

To use this value navigate to `toolbox_label.js` and add the following lines to
your `init` method.

```js
const cssConfig = this.toolboxItemDef_['cssconfig'];
// Add the class.
if (cssConfig) {
  this.label.classList.add(cssConfig['label']);
}
```

The above code will add the class to the label. Now, in `toolbox_style.css` add
the below CSS to make the label bold.

```css
.customLabel {
  font-weight: bold;
}
```

### The result

If you refresh your app you should now see a bold dark gray label at the
top of your toolbox.

<Image
  src="/images/codelabs/custom-toolbox/final_toolbox.png"
  alt="The toolbox with a label that is now bolded."
  className="codelabImage"
/>

---

### Packages Docs Docs Codelabs Custom Toolbox Change The Category HTML (`packages/docs/docs/codelabs/custom-toolbox/change-the-category-HTML.mdx`)

---
description: How to change the HTML used by a category.
---

import Image from '@site/src/components/Image';

# Customizing a Blockly toolbox

## 7. Change the category HTML

If you only need to change the CSS, like we did in the previous section, then using the cssConfig is a great choice.
However, if you need to change the html, maybe to add text, an image, or anything else, you can override
the corresponding method that creates the dom. In this example, we'll add an `<img>`
to our category by overriding the `createIconDom_` method.

### Change the element for our icon

By default, the `createIconDom_` method adds a `<span>` element for the category
icon. Note that you can override this to create other types of elements, if needed.

Add the following method to `custom_category.js`:

```js
/** @override */
createIconDom_() {
  const icon = document.createElement('span');
  icon.textContent = '🧰';
  return icon;
}
```

### The result

If you refresh the running app, you should now see the toolbox emoji on top of all your categories.
Keep in mind, this method of changing the HTML changed it for *all* categories. 
This means that you have effectively removed the custom gear icon that was previously on your "Logic" category.

<Image
  src="/images/codelabs/custom-toolbox/image_toolbox.png"
  alt="A toolbox with a toolbox emoji on top of the category label."
  className="codelabImage"
/>

---

### Packages Docs Docs Codelabs Custom Toolbox Change The Look Of A Category (`packages/docs/docs/codelabs/custom-toolbox/change-the-look-of-a-category.mdx`)

---
description: How to change the look of a category.
---

import Image from '@site/src/components/Image';

# Customizing a Blockly toolbox

## 4. Change the look of a category

### Change the background of the category

In the default `ToolboxCategory` class, the `addColourBorder_` method adds a strip of color next
to the category name. We can override this method in order to add colour to the entire category div.

Add the following code to your `CustomCategory` class.

```js
/** @override */
addColourBorder_(colour){
  this.rowDiv_.style.backgroundColor = colour;
}
```

The `colour` passed in is calculated from the `categorystyle` attribute set on the category definition.

For example, you can see in your `toolbox.js` file that the "Logic" category definition looks like:

```js
{
  kind: 'category',
  name: 'Logic',
  categorystyle: 'logic_category',
  ...
}
```

The logic_category style (defined in Blockly's theme) is:

```js
"logic_category": {
    "colour": "210"
  }
```

You can also set the colour directly via the `color` attribute on the category definition.

```json
{
  kind: 'category',
  name: 'Logic',
  colour: '210',
}
```

For more information on Blockly styles please visit the [themes documentation](/guides/configure/appearance/themes#category-style).

### Add some CSS

Open your application page to see your updated toolbox. Your toolbox should look
similar to the below toolbox.

<Image
  src="/images/codelabs/custom-toolbox/colored_toolbox.png"
  alt="A toolbox with colors that expand the across the entire category."
  className="codelabImage"
/>

We are going to add some CSS to make it easier to read, and to space out our categories.

Create a file named `toolbox_style.css` in the same directory as `index.js`.
Then, import the new file in `index.js`:

```js
import './toolbox_style.css';
```

:::note
Importing a `.css` file into a JavaScript file isn't standard JavaScript. It 
works here because this project's webpack config (`webpack.config.js`) has a 
rule that bundles and injects `.css` files.
:::

Copy and paste the following CSS into your `toolbox_style.css` file.

```css
/* Makes our label white. */
.blocklyToolboxCategoryLabel {
  color: white;
}
/* Adds padding around the group of categories and separators. */
.blocklyToolboxCategoryGroup {
  padding: 0.5em;
}
/* Adds space between the categories, rounds the corners and adds space around the label. */
.blocklyToolboxCategory {
  padding: 3px;
  margin-bottom: 0.5em;
  border-radius: 4px;
}
```

### The result

Open the running application to see your toolbox. 

<Image
  src="/images/codelabs/custom-toolbox/styled_toolbox.png"
  alt="Toolbox with category corners that are rounded and white text."
  className="codelabImage"
/>

---

### Packages Docs Docs Codelabs Custom Toolbox Change The Look Of A Selected Category (`packages/docs/docs/codelabs/custom-toolbox/change-the-look-of-a-selected-category.mdx`)

---
description: How to change the look of a selected category.
---

import Image from '@site/src/components/Image';

# Customizing a Blockly toolbox

## 5. Change the look of a selected category

### Change the selected appearance
Open your application and click on a category. You will see that it
doesn't give any indication that it has been clicked. Worse than that, if you
click on the category a second time the background color will disappear.

To fix this, we are going to override the `setSelected` method to change the look
of a category when it has been clicked. In the default category class this method
adds a colour to the entire row when a category is selected. Since we have already
expanded the colour over our entire div, we are going to change the background
color of the div to white, and the text to the color of the category when it has
been selected.

The styling code can be seen below:

```js
/** @override */
setSelected(isSelected){
   // We do not store the label span on the category, so use getElementsByClassName.
   var labelDom = this.rowDiv_.getElementsByClassName('blocklyToolboxCategoryLabel')[0];
   if (isSelected) {
     // Change the background color of the div to white.
     this.rowDiv_.style.backgroundColor = 'white';
     // Set the colour of the text to the colour of the category.
     labelDom.style.color = this.colour_;
   } else {
     // Set the background back to the original colour.
     this.rowDiv_.style.backgroundColor = this.colour_;
     // Set the text back to white.
     labelDom.style.color = 'white';
   }
}
```

### Include accessibility features

Since `setSelected` overrides without calling `super.setSelected()`, this version replaces the parent's behaviour entirely.
The parent method does one thing we still need: it sets the ARIA state to `State.SELECTED` 
so that screen readers can announce when a category is selected. 

There are multiple ways to handle this:
1. Call `super.setSelected` (preferred)
1. Take a look at the parent implementation and add the same functionality.

In this case, add a call to `super.setSelected`. This will ensure that if 
additional functionality is added to the parent class in the future, your `setSelected`
will properly inherit it.  

Add the full `setSelected` function into `custom_category.js`:

```js
/** @override */
setSelected(isSelected){
  super.setSelected(isSelected);

   // We do not store the label span on the category, so use getElementsByClassName.
   var labelDom = this.rowDiv_.getElementsByClassName('blocklyToolboxCategoryLabel')[0];
   if (isSelected) {
     // Change the background color of the div to white.
     this.rowDiv_.style.backgroundColor = 'white';
     // Set the colour of the text to the colour of the category.
     labelDom.style.color = this.colour_;
   } else {
     // Set the background back to the original colour.
     this.rowDiv_.style.backgroundColor = this.colour_;
     // Set the text back to white.
     labelDom.style.color = 'white';
   }
}
```

:::note 
Review the parent implementation whenever you override a Blockly method, and call
`super()` unless you have a strong reason not to. This helps you properly 
implement non-visual processes that are important. 
:::

### The result

Open the running application and click on the "Logic" category. You should now see a white
category with a colored label.

<Image
  src="/images/codelabs/custom-toolbox/category_selected.png"
  alt="A toolbox with all categories colored except for the first category that has a white background."
  className="codelabImage"
/>

---

### Packages Docs Docs Codelabs Custom Toolbox Setup (`packages/docs/docs/codelabs/custom-toolbox/setup.mdx`)

---
description: Setting up the "Customizing a Blockly toolbox" codelab.
---

import Image from '@site/src/components/Image';

# Customizing a Blockly toolbox

## 2. Setup

### Create the application

Use the [`npx @blockly/create-package app`](https://www.npmjs.com/package/@blockly/create-package) command to create a standalone application that contains a sample setup of Blockly, including custom blocks and a display of the generated code and output.

1. Run `npx @blockly/create-package app custom-toolbox-codelab` in your terminal. This will create a Blockly application in the folder `custom-toolbox-codelab`.
1. Use `cd` to move into the new directory: `cd custom-toolbox-codelab`.
1. Run `npm start` to start the server and run the sample application.
1. The sample app will automatically run in the browser window that opens.

The local address in the address bar of your browser starting with `http://localhost:` shows where your app is.
If you accidentally close this window or tab, you can re-open this local address to view the app as long as `npm start` is still running.

The initial application has a toolbox definition included in the `toolbox.js` file. 
This codelab focuses on customizing the *appearance* of a Blockly toolbox rather than the content and categories, but feel free to experiment with customizing the content of the toolbox in `toolbox.js`.   

### Change the storage key

Before setting up the rest of the application, **change the storage key** used for this codelab application. This will ensure that the workspace is saved in its own storage, separate from the regular sample app, so that it doesn't interfere with other demos. 

In `serialization.js`, change the value of `storageKey` to some unique string. `customToolboxWorkspace` will work:

```js
// Use a unique storage key for this codelab
const storageKey = 'customToolboxWorkspace';
```

### Explore the starter code

Take a moment to explore the code you just created in the `custom-toolbox-codelab` folder. If you'd like a more in-depth explanation of all of the code in the sample app, check out the [getting started codelab](/codelabs/getting-started/codelab-overview) which goes through creating this sample app from scratch.  

For a briefer outline of the code, visit the [sample app overview](/guides/get-started/sample-app-overview/) page for an overview of the included files and tooling.

---

### Packages Docs Docs Codelabs Custom Toolbox Summary (`packages/docs/docs/codelabs/custom-toolbox/summary.mdx`)

---
pagination_next: null
description: Summary of the "Customizing a Blockly toolbox" codelab.
---

# Customizing a Blockly toolbox

## 9. Summary

The toolbox can be customized in a variety of ways to make it work for your application. In this codelab you learned:

- How to create a custom category.
- What method to override to change how the colour of the category is applied.
- What method to override to change the look of the category when selected.
- How to add an icon by adding a custom CSS class to the icon div.
- How to change what HTML Elements are used for different parts of a category.
- How to create a custom toolbox item.
  You can find the code for the [completed custom toolbox](https://github.com/RaspberryPiFoundation/blockly/docs/docs/codelabs/custom-toolbox/complete-code) on GitHub.

---

### Packages Docs Docs Codelabs Getting Started Add Blockly Libraries (`packages/docs/docs/codelabs/getting-started/add-blockly-libraries.mdx`)

---
description: How to add Blockly libraries to an app.
---

# Getting started with Blockly

## 3. Add Blockly libraries

Blockly releases are [published on npm](https://www.npmjs.com/package/blockly) regularly.
There are multiple ways to use Blockly in your project, but for this codelab you will install Blockly with npm.

### Install dependencies and run your app

Use the following instructions to install dependencies and start the app: 

1. Install [node.js and npm](https://docs.npmjs.com/downloading-and-installing-node-js-and-npm) if you haven't already.
2. Navigate to the starter code folder `packages/docs/docs/codelabs/getting-started/starter-code/` 
in your terminal.
3. Run `npm install` in your terminal. npm install will install the necessary dependencies that are defined in `package.json`, including Blockly. 
4. Run `npm start` in your terminal. 

After following these steps, a browser page should open automatically, or you can copy-paste the address that includes `localhost` into your browser. 
The page should be blank. Don't worry, you'll add in your Blockly workspace in the following steps. 

### Alternate imports

There are many ways to import a library in JavaScript, and this tutorial does not cover all of them. For samples that show how to integrate Blockly in your project, look at the `examples` folder in [blockly-samples](https://github.com/RaspberryPiFoundation/blockly-samples).

---

### Packages Docs Docs Codelabs Getting Started Create A Blockly Workspace (`packages/docs/docs/codelabs/getting-started/create-a-blockly-workspace.mdx`)

---
description: How to add a workspace to your app.
---

import Image from '@site/src/components/Image';

# Getting started with Blockly

## 5. Create a Blockly workspace

In this section you will learn how to add a workspace to your app, including how to define a toolbox.

### Parts of Blockly

A Blockly workspace has two main components:

- A toolbox that contains all blocks that are available to the user (the grey area on the left).
- The area where the user assembles their blocks (the white area on the right).  

<Image
  src="/images/codelabs/getting-started/workspace_with_toolbox.png"
  alt="A Blockly toolbox and workspace with three connected blocks in the workspace."
  className="codelabImage"
/>   

Users can drag blocks out of the toolbox and into their workspace to assemble a program. 

The toolbox may be organized into categories (a *category* toolbox) or have all blocks visible at all times (a *flyout* toolbox). Toolboxes may contain both single blocks or groups of blocks. 
A well-organized toolbox helps the user to explore the available blocks and understand the capabilities of the underlying system.

A toolbox is defined as a JavaScript object and passed into the workspace constructor through an options struct.

For more information on this JSON format and toolbox configuration, including category creation, please see our [toolbox documentation](/guides/configure/toolboxes/toolbox).
If you'd like to customize the appearance of your toolbox, you can consult the [toolbox customization codelab](/codelabs/custom-toolbox/codelab-overview/).

### Define the toolbox

Find the file in the `src/` folder called `toolbox.js`. Add the following JSON toolbox definition to `toolbox.js`: 

```js
export const toolbox = {
  kind: 'flyoutToolbox',
  contents: [
    {
      kind: 'block',
      type: 'controls_repeat_ext',
      inputs: {
        TIMES: {
          shadow: {
            type: 'math_number',
            fields: {
              NUM: 3,
            },
          },
        },
      },
    },
    {
      kind: 'block',
      type: 'text',
    },
  ]
};
```

This defines a flyout toolbox with a loop block and a text block.

### Injection

Adding a Blockly workspace to a page is called _injection_, because the workspace is injected into a `div` that already exists on the page.

To do this you call the function `Blockly.inject(container, options)`, which takes two arguments:

- `container` is where the Blockly workspace should be placed on the page. It can be an `Element`, an ID string, or a CSS selector.
- `options` is a dictionary of configuration options.

For this codelab, the workspace goes into the `div` with the id `"blocklyDiv"`, which you already created in `index.html`. 

```html
<div id="blocklyDiv"></div>
```

### Create the workspace

Now, in `src/index.js`, import the toolbox you just created. 
Then, set up variables for each major div in `index.html` so that you can later reference these UI elements.
Finally, inject Blockly using the toolbox you just created. 

Copy and paste the full code into your `index.js`: 
```js
import * as Blockly from 'blockly';
import {toolbox} from './toolbox';
import './index.css'

// Set up UI elements and inject Blockly
const codeDiv = document.getElementById('generatedCode').firstChild;
const outputDiv = document.getElementById('output');
const blocklyDiv = document.getElementById('blocklyDiv');

const ws = Blockly.inject(blocklyDiv, {toolbox});
```

`Blockly.inject` allows you to specify some options regarding what your workspace and toolbox look like. 
In this case, the only configuration option you selected was `toolbox` which lets you add a toolbox definition to your instance of Blockly. 

The `options` struct offers many additional options which give you significant control over your Blockly's instance.

For example: 
- `scrollbars`: Whether to show scrollbars in the workspace. If a toolbox is a flyout toolbox (like the one you just defined), `scrollbars` defaults to `false`. 
- `horizontalLayout`: Whether to display the toolbox horizontally (`true`) or vertically (`false`) in the workspace. Defaults to `false`/vertical. 
- `toolboxPosition`: Controls the position of the toolbox in the workspace. It defaults to the left side if the layout is vertical. 
- `maxBlocks`: The maximum number of blocks that may be created in the workspace. 

There are more options available which can change the appearance or behavior of Blockly. For a list of all the available options, see the [configuration](/guides/configure/configuration_struct#the-options-dictionary) documentation.

### Check your work

Make sure that all the files you've added code to (`index.html`, `toolbox.js`, and `index.js`) are saved. You may also need to refresh your `localhost` page. 

You should now see your Blockly workspace. Click on one of the blocks in the toolbox and drag it into the workspace, then let go. You've just added your first block to the workspace!

:::tip
Blockly is keyboard navigable. Check out the [keyboard navigation guide](/guides/configure/keyboard-nav/#try-it), then try to add another block without using your mouse.
:::

<Image
  src="/images/codelabs/getting-started/full_page_first_toolbox.png"
  alt="A webpage with a space for generated code, a Blockly toolbox with two blocks in it, and a Blockly workspace with one block in it."
  className="codelabImage"
/>

---

### Packages Docs Docs Codelabs Getting Started Create A Custom Block (`packages/docs/docs/codelabs/getting-started/create-a-custom-block.mdx`)

---
description: How to create a custom block.
---

import Image from '@site/src/components/Image';

# Getting started with Blockly

## 6. Create a custom block

Blockly provides various blocks for math, strings, loops, and more. But the real power of a Blockly application comes from your custom blocks. 
You can define blocks that are related to your application, such as one that plays a song, makes a robot move on the screen, or reports the temperature from a connected sensor.

In Blockly, a _block definition_ describes how a block looks and behaves. This includes its text, colour, and shape. It may also include which other blocks it can connect to.

Blocks can be defined in either JavaScript or JSON. The developer site has a full article on [how to define a block](/guides/create-custom-blocks/define/block-definitions#how-to-create-block-definitions).
There are also opinionated guides on topics such as [block design](/guides/design/blocks) and [block appearance](/guides/design/appearance) that reflect recommended best practices when creating blocks.

### Define the add_text block

Now, build a block that adds text to the output div of this workspace.

Find the `text.js` file in `src/blocks/`. Specify the block definition by adding the following code to `text.js`: 

```js
import * as Blockly from 'blockly/core';

// Create a custom block called 'add_text' that adds
// text to the output div on the sample app.
const addText = {
  type: 'add_text',
  message0: 'Add text %1',
  args0: [
    {
      type: 'input_value',
      name: 'TEXT',
      check: 'String',
    },
  ],
  previousStatement: null,
  nextStatement: null,
  colour: 160,
  tooltip: '',
  helpUrl: '',
};
```

This block definition defines a block called `add_text` that has one `string` value input called `TEXT`. There is a message on the block that says "Add text" before the input. 
The `add_text` block also has a previous connection and a next connection, allowing it to be stacked vertically. 

The page on [Block structure in JSON](/guides/create-custom-blocks/define/structure-json) is a good resource for understanding the parts of a JSON block definition. 

### Create Block Definition

After declaring the JSON definition for the block, turn it into the full block definition that Blockly can register. 
To do that, call `createBlockDefinitionsFromJsonArray` which turns the raw JSON object into the JavaScript block definition that Blockly will use.
Save that definition as an object called `blocks`. 
Add the following code to the end of `text.js`, after your `addText` object.

```js
// Create the block definitions for the JSON-only blocks.
// This does not register their definitions with Blockly.
// This file has no side effects!
export const blocks = Blockly.common.createBlockDefinitionsFromJsonArray([
  addText,
]);
```

### Register the custom block

Now register the block. Add the following import statement and code to the top of the `index.js` file:

```js
import {blocks} from './blocks/text';
```

Just after the import statements, insert the following code in `index.js`. 
This code uses the block definition that you just saved in order to add the custom `add_text` block to the list of available blocks: 

```js
Blockly.common.defineBlocks(blocks);
```

### Add the custom block to the toolbox

Now, update the toolbox to include the new block, by adding `{'kind': 'block', 'type': 'add_text'}` to the `toolbox` definition. The full toolbox should now be: 

```js
export const toolbox = {
  kind: 'flyoutToolbox',
  contents: [
    {
      kind: 'block',
      type: 'controls_repeat_ext',
      inputs: {
        TIMES: {
          shadow: {
            type: 'math_number',
            fields: {
              NUM: 3,
            },
          },
        },
      },
    },
    {
      kind: 'block',
      type: 'text',
    },
    {
      kind: 'block',
      type: 'add_text',
    },
  ]
};
```

Again, ensure that your files are saved, then check your `localhost` Blockly page. You should now see your custom `add_text` block in your toolbox! 

<Image
  src="/images/codelabs/getting-started/full_page_second_toolbox.png"
  alt="A webpage with a space for generated code, a Blockly toolbox with three blocks in it, and a Blockly workspace."
  className="codelabImage"
/>   

### The block factory

This step discussed how to manually define custom blocks in Blockly. Once you've completed the entire codelab, we recommend that you check out our [block factory tool](/guides/create-custom-blocks/blockly-developer-tools), which helps automate part of this process.

---

### Packages Docs Docs Codelabs Getting Started Create Base App (`packages/docs/docs/codelabs/getting-started/create-base-app.mdx`)

---
description: How to set up the base for your app.
---

# Getting started with Blockly

## 4. Add basic HTML and CSS

### Create the HTML
Open the `src/` folder and find the file called `index.html`. 
`index.html` will specify the basic structure for your app, and will include a `div` (here called `blocklyDiv`) that you'll later inject Blockly into. 

Copy and paste the following HTML into your `index.html` file:

```html
<!doctype html>
<html>
  <head>
    <meta charset="utf-8" />
    <title>Blockly Sample App</title>
  </head>
  <body>
    <div id="pageContainer">
      <div id="outputPane">
        <pre id="generatedCode"><code></code></pre>
        <div id="output"></div>
      </div>
      <div id="blocklyDiv"></div>
    </div>
  </body>
</html>
```

### Examine the CSS

The css for the app is already included in the `index.css` file. This codelab includes basic styling for the webpage. 

If you would like to change the appearance of Blockly's toolbox and workspace, you can check out the [customizing your themes codelab](/codelabs/theme-extension-identifier/codelab-overview/). 
For more fine-grained styling of components and blocks, you can consult the [CSS codelab](/codelabs/css/codelab-overview/). 

### Import Blockly

At various points throughout this codelab, you'll import Blockly in different ways.
Since you already installed Blockly using npm, you can freely import Blockly into your files without an additional step. 
Add the following import statement to `index.js`:

```js
import * as Blockly from 'blockly';
``` 

Importing Blockly this way includes the core Blockly library, the built-in blocks, and the [English translations](/guides/configure/translations). 
It also includes some other pieces you need later in this codelab, like the [JavaScript code generator](/codelabs/getting-started/generate-javascript-code).

However, sometimes you may only want to import the core Blockly library. In that case, you could import Blockly using:

```js
import * as Blockly from 'blockly/core';
```

---

### Packages Docs Docs Codelabs Getting Started Generate JavaScript Code (`packages/docs/docs/codelabs/getting-started/generate-javaScript-code.mdx`)

---
description: How to generate JavaScript code.
---

import Image from '@site/src/components/Image';

# Getting started with Blockly

## 8. Generate JavaScript code

Blockly can convert blocks into strings of code in a process called _code generation_. 
Blocks on their own don't do anything, but you can make them generate code that does, and then execute that code.
The code execution step is application-specific and therefore outside of Blockly's scope. It is up to you to determine if, when, and how to execute the strings of code that Blockly generates. 

Code generation and execution is how you get from a list of blocks to a program that *does* something.
But before you determine how your application will execute code, you first need to tell Blockly how to generate the code. 

In this step, you'll set up code generation for the `add_text` block. 

### The language generator

A _language generator_ defines the rules for generating a specific language (such as indentation).

By default, Blockly can generate code from blocks for five languages: Dart, JavaScript, Lua, PHP, and Python. 
You can also create a custom language generator to generate code in a different language, which the [custom generator codelab](/codelabs/custom-generator/codelab-overview/) describes. 

### Add a block generator

When Blockly generates JavaScript code for blocks in a workspace, it translates each block into code. By default, it knows how to translate all library-provided default blocks into JavaScript code. However, for any custom blocks, you need to specify your own translation functions. These are called _block generators_.

Find the `javascript.js` file in `src/generators/`.

The block generator for `add_text` will first recursively generate the code for the input `TEXT`. 
Then, it provides the function that will add text to the output area using `generator.provideFunction_`. 
`provideFunction_` is an advanced code generation feature that allows you to specify a function that will be defined just once, even if the block is used multiple times.

Finally, the block generator creates the function call that will be generated for this block. 

Add the following code to `src/generators/javascript.js`:

```js
import {Order} from 'blockly/javascript';

export const forBlock = Object.create(null);

forBlock['add_text'] = function (block, generator) {
  // Generate the code for the input block.
  const text = generator.valueToCode(block, 'TEXT', Order.NONE) || "''";
  // Create the function for this block.
  const addText = generator.provideFunction_(
    'addText',
    `function ${generator.FUNCTION_NAME_PLACEHOLDER_}(text) {

  // Add text to the output area.
  const outputDiv = document.getElementById('output');
  const textEl = document.createElement('p');
  textEl.innerText = text;
  outputDiv.appendChild(textEl);
}`,
  );
  // Generate the function call for this block.
  const code = `${addText}(${text});\n`;
  return code;
};
```

With this translation function, the `add_text` block with a string input of "Hello, World!":

<Image
  src="/images/codelabs/getting-started/add_text_block.png"
  alt=""
  className="codelabImage"
/>

translates into the JavaScript code:

```javascript
function addText(text) {
  // Add text to the output area.
  const outputDiv = document.getElementById('output');
  const textEl = document.createElement('p');
  textEl.innerText = text;
  outputDiv.appendChild(textEl);
}

addText('Hello, World!');
```

### Register the block code generator

Finally, register the block generator for `add_text` with Blockly's JavaScript generator.

Add the following imports to the `index.js` file:
```js
import {forBlock} from './generators/javascript';
import {javascriptGenerator} from 'blockly/javascript';
```

Note that the `index.js` file should now have 7 total import statements: 
```js
import * as Blockly from 'blockly';
import {blocks} from './blocks/text';
import {forBlock} from './generators/javascript';
import {javascriptGenerator} from 'blockly/javascript';
import {save, load} from './serialization';
import {toolbox} from './toolbox';
import './index.css';
```

Now add the `forBlock` for `add_text` into Blockly's javascriptGenerator so that Blockly can generate the code for your block.
The following `Object.assign` statement *registers* your block generator by adding it to the `forBlock` object of the `javascriptGenerator`.
Adding this assignment means that `add_text` is part of the list of blocks that `javascriptGenerator` knows how to generate code for.

Put the following line of code into `index.js`, just below ```Blockly.common.defineBlocks(blocks);```

```js
Object.assign(javascriptGenerator.forBlock, forBlock);
```

For more information on block generators, read the [generating code](/guides/create-custom-blocks/code-generation/overview) page on the developer site.

---

### Packages Docs Docs Codelabs Getting Started Run Generated Code (`packages/docs/docs/codelabs/getting-started/run-generated-code.mdx`)

---
description: How to run generated code.
---

import Image from '@site/src/components/Image';

# Getting started with Blockly

## 9. Run generated code

Executing generated code is always the responsibility of the application. 
Blockly turns blocks into code, and what you do with that code is up to you. 

For this codelab, you'll display the generated code and use `eval` to run it. Then you'll show the output beneath the code.

### Set up the code execution

The `runCode` function uses Blockly's javascriptGenerator to generate the code for the blocks on the workspace. 
Then it displays the code in the codeDiv, resets the outputDiv, and evaluates the JavaScript code. 

Paste the following code into `index.js`, right below your Blockly injection:

```js
// This function resets the code and output divs, shows the
// generated code from the workspace, and evals the code.
// In a real application, you probably shouldn't use `eval`.
const runCode = () => {
  const code = javascriptGenerator.workspaceToCode(ws);
  codeDiv.innerText = code;

  outputDiv.innerHTML = '';

  // Wrap `eval` in a `try/catch` so that any runtime errors are 
  // logged to the console, instead of failing quietly.
  try {
    eval(code);
  } catch (error) {
    console.log(error);
  }
};
```

### Run the code

Now, call the new `runCode` function. 
First, consider the scenario when your app is first loading up. After loading in the saved data, the code should run automatically.

Add a call to `runCode` just after your call to `load`. 

Now your `index.js` file should have:

```js
// Load the initial state from storage and run the code.
load(ws);
runCode();
```

Since this code is simply declared in the `index.js` file and isn't a part of any function, it'll only run whenever the workspace is loaded (or reloaded). 
You also want the code to run any time a block is added or changed in the workspace. This sounds like another job for change listeners.

### Add a change listener

Similar to the last change listener, you'll want to exclude certain types of events. This time, in addition to ignoring UI Events, ignore the event that fires when the workspace has finished loading, since you already added a call to `runCode` after `load`. 
Disregard anything that fires when a block is currently being dragged, so that you don't run the code for an invalid state. 
For all other events, this change listener will call `runCode`.

Copy and paste the following code at the bottom of `index.js`:

```js 
// Whenever the workspace changes meaningfully, run the code again.
ws.addChangeListener((e) => {
  // Don't run the code when the workspace finishes loading; we're
  // already running it once when the application starts.
  // Don't run the code during drags; we might have invalid state.
  if (
    e.isUiEvent ||
    e.type == Blockly.Events.FINISHED_LOADING ||
    ws.isDragging()
  ) {
    return;
  }
  runCode();
});
```

### A note on eval

Executing scripts with eval is not always the safest option - we use it here for simplicity. If you intend to run the user's blocks in production, check out the <a href="https://github.com/NeilFraser/JS-Interpreter">JS Interpreter project</a>. This project is separate from Blockly, but was specifically written for Blockly.

### Test it

Run the app and try it out! Try making a simple program by putting the add text block, with a text input, into a loop. 

<Image
  src="/images/codelabs/getting-started/full_page_finished.png"
  alt="A complete Blockly workspace, with 3 blocks that generate code which prints Hello, World! five times."
  className="codelabImage"
/>

---

### Packages Docs Docs Codelabs Getting Started Save Load Workspace (`packages/docs/docs/codelabs/getting-started/save-load-workspace.mdx`)

---
description: How to save and load your workspace.
---

# Getting started with Blockly

## 7. Save/load workspace

You now have a Blockly workspace. However, if you reload the page, you'll find that any blocks you've dragged into the workspace will disappear.
Your users likely won't want their blocks to vanish, but you can fix this by saving the state of the workspace and loading it back in the next time they visit the site. 
For this codelab, you'll save the state of the workspace to local browser storage. 

### Add the save method

Open `src/serialization.js`. Set a unique storage key for this codelab. Then add a function `save` which takes the Blockly workspace, exports its state to a JavaScript object, then saves that object to local storage. 

Add the following code to the `serialization.js` file:

```js
import * as Blockly from 'blockly/core';

const storageKey = 'getting-started-codelab/mainWorkspace';

/**
 * Saves the state of the workspace to browser's local storage.
 * @param {Blockly.Workspace} workspace Blockly workspace to save.
 */
export const save = function (workspace) {
  const data = Blockly.serialization.workspaces.save(workspace);
  window.localStorage?.setItem(storageKey, JSON.stringify(data));
};
```

### Add the load method

When a user opens or reloads the page, the blocks in local storage should be loaded back into the workspace. The following `load` function handles this by checking for items in local storage and loading them into the workspace. 

In the `serialization.js` file, add this code: 

```js
/**
 * Loads saved state from local storage into the given workspace.
 * @param {Blockly.Workspace} workspace Blockly workspace to load into.
 */
export const load = function (workspace) {
  const data = window.localStorage?.getItem(storageKey);
  if (!data) return;

  // Don't emit events during loading.
  Blockly.Events.disable();
  Blockly.serialization.workspaces.load(JSON.parse(data), workspace, false);
  Blockly.Events.enable();
};
```

### Events

You may have noticed that the `load` function disables events from emitting while loading the workspace. 
Every change on the workspace, like dragging a block or connecting blocks, triggers an *event*. You can listen in to the *event stream* to run code when certain events happen.

For the `load` function, disabling events while loading will help prevent unexpected behavior, since some parts of Blockly listen to the event stream to know when to execute.

You can take advantage of the event stream to know when to call the `save` and `load` functions. 

### Add a Change Listener
In `src/index.js`, add the following import statement.

```js
import {save, load} from './serialization';
```

Now, add a change listener at the bottom of `index.js` to listen to the event stream and save the workspace after events. 
Additionally, add a call to `load` outside of the change listener, so that your app finds the saved blocks on initial load.  

```js
load(ws);

// Every time the workspace changes state, save the changes to storage.
ws.addChangeListener((e) => {
  save(ws);
});
```

This change listener is not yet complete, since there are some types of events that you shouldn't save after. 
UI changes (e.g. scrolling, zooming, or opening toolbox categories) change how the workspace *looks* but don't change the state of the blocks. 
Since you're only saving the blocks, you don't have to save after these types of events. 

Here's the full change listener code, including the call to `load` outside of the change listener: 

```js
load(ws);

// Every time the workspace changes state, save the changes to storage.
ws.addChangeListener((e) => {
  // UI events are things like scrolling, zooming, etc.
  // No need to save after one of these.
  if (e.isUiEvent) return;
  save(ws);
});
```

To learn more about the events stream, see the [Events documentation](/guides/configure/events/).

### Testing the changes

Now, test the code. Add some blocks, then reload the page. The workspace should still contain the blocks you added.

---

### Packages Docs Docs Codelabs Getting Started Setup (`packages/docs/docs/codelabs/getting-started/setup.mdx`)

---
description: Setting up the "Getting started with Blockly" codelab.
---

# Getting started with Blockly

## 2. Setup

### Download the sample code

You can get the sample code for this code by either downloading the zip here:

[Download zip](https://github.com/RaspberryPiFoundation/blockly/archive/main.zip)

or by cloning this git repo:

```bash
git clone https://github.com/RaspberryPiFoundation/blockly.git
```

If you downloaded the source as a zip, unpacking it should give you a root folder named `blockly-main`.

The relevant files are in the `packages/docs/docs/codelabs/getting-started/` folder. There are two versions of the app:

- `starter-code/`: The starter code that you'll build upon in this codelab.
- `complete-code/`: The code after completing the codelab, in case you get lost or want to compare to your version.

The starter code folder contains:

- `src/`: Where you'll put your code. The necessary files are already included. 
- `package-lock.json`: Keeps track of the dependencies.
- `package.json`: Stores basic information about the app. 
- `webpack.config.js`: The configuration for webpack, which handles the application bundling and running the server.

---

### Packages Docs Docs Codelabs Getting Started The End (`packages/docs/docs/codelabs/getting-started/the-end.mdx`)

---
pagination_next: null
description: Summary of the "Getting started with Blockly" codelab.
---

# Getting started with Blockly

## 10. The End

And with that, you're done with your first Blockly codelab! 

### Sample app

What you've built today is almost identical to Blocky's sample app.
To make your own Blockly project, you can follow the instructions to install the sample app from the [sample app overview](/guides/get-started/sample-app-overview) or continue building off this codelab. 

One key difference to note between this codelab and the sample app is the toolbox. 
The sample app's toolbox is a category toolbox, which changes some of the default [configuration](/guides/configure/configuration_struct#the-options-dictionary) values discussed in the [create a Blockly workspace](/codelabs/getting-started/create-a-blockly-workspace) step. 
For instance, when using a category toolbox, the `scrollbars` option will default to `true`, making scrollbars appear on the workspace automatically. 

The sample app also includes *all* of Blockly's built-in blocks. We strongly recommend against using every built-in block in your toolbox. Instead, you should carefully select the blocks that your users may need. 

### Next steps

If you'd like to continue playing with the app, we suggest adding or changing the available blocks. 

To create another custom block, try using the [block factory tool](/guides/create-custom-blocks/blockly-developer-tools), which provides a visual interface for creating new blocks.  

For more documentation and codelabs, visit the [Blockly developer site](/).

Additionally, Blockly has an active [developer forum](https://groups.google.com/g/blockly). Please drop by and say hello. We're happy to answer any questions or give advice on best practices for building an app with Blockly. Feel free to show us your prototypes early; collectively we have a lot of experience and can offer help.

---

### Packages Docs Docs Codelabs Theme Extension Identifier Customize Block Styles (`packages/docs/docs/codelabs/theme-extension-identifier/customize-block-styles.mdx`)

---
description: How to use a theme to set the colours of blocks.
---

import Image from '@site/src/components/Image';

# Customizing your themes

## 6. Customize Block Styles

A block style currently only holds three different colour properties. They are 'colourPrimary',
'colourSecondary' and 'colourTertiary'. This value can either be defined as a hex value or as a hue.
For more information on block styles visit our themes [documentation.](/guides/configure/appearance/themes#block-style)

Add a `blockStyles` section to the theme definition in `src/index.js` so that it now looks like the below.
There is one block style for each category in the sample app's toolbox:

```
/* Detailed source-code truncated for AI context efficiency. */
```

### Test it

Refresh the page, then click on different categories and drag out blocks. You should see the colours that you applied show up.

<Image
  src="/images/codelabs/theme-extension/block_styles.png"
  alt="Blockly workspace and flyout with customized block colours."
  className="codelabImage"
/>

---

### Packages Docs Docs Codelabs Theme Extension Identifier Customize Category Styles (`packages/docs/docs/codelabs/theme-extension-identifier/customize-category-styles.mdx`)

---
description: How to use a theme to set the colours of categories.
---

import Image from '@site/src/components/Image';

# Customizing your themes

## 5. Customize Category Styles

A category style currently only holds a colour property. It is the colour of the category on the toolbox.
This value can either be defined as a hex value or as a hue. Usually these colours should be the same as
the colourPrimary on the majority of blocks in the category making it easy for users to tell what blocks
belong in what category.

Add a `categoryStyles` section to the theme definition in `src/index.js`. The sample app's toolbox includes
Logic, Loops, Math, Text, Lists, Variables, and Functions categories, so we'll provide a style for each one:

```js
Blockly.Themes.Halloween = Blockly.Theme.defineTheme('halloween', {
  base: Blockly.Themes.Classic,
  categoryStyles: {
    logic_category: {
      colour: '#8b4513',
    },
    loop_category: {
      colour: '#85E21F',
    },
    math_category: {
      colour: '#542788',
    },
    text_category: {
      colour: '#FE9B13',
    },
    list_category: {
      colour: '#4a148c',
    },
    variable_category: {
      colour: '#cc0000',
    },
    procedure_category: {
      colour: '#1b5e20',
    },
  },
  componentStyles: {
    workspaceBackgroundColour: '#ff7518',
    toolboxBackgroundColour: '#F9C10E',
    toolboxForegroundColour: '#fff',
    flyoutBackgroundColour: '#252526',
    flyoutForegroundColour: '#ccc',
    flyoutOpacity: 1,
    scrollbarColour: '#ff0000',
    insertionMarkerColour: '#fff',
    insertionMarkerOpacity: 0.3,
    scrollbarOpacity: 0.4,
    cursorColour: '#d0d0d0',
    blackBackground: '#333',
  },
});
```

### Test it

Refresh the page. The colour displayed next to each toolbox category should display your new colours.
Clicking on a category will highlight the row with your new colour.

<Image
  src="/images/codelabs/theme-extension/customized_categories.png"
  alt="Customized category colours on the toolbox."
  className="codelabImage"
/>

---

### Packages Docs Docs Codelabs Theme Extension Identifier Customize Components (`packages/docs/docs/codelabs/theme-extension-identifier/customize-components.mdx`)

---
description: How to use a theme to set the colours of components.
---

import Image from '@site/src/components/Image';

# Customizing your themes

## 4. Customize Components

Within the Halloween theme definition in `src/index.js`, you can customize the colours of multiple components. Update the theme definition to add the `componentStyles` shown below:

```js
Blockly.Themes.Halloween = Blockly.Theme.defineTheme('halloween', {
  base: Blockly.Themes.Classic,
  componentStyles: {
    workspaceBackgroundColour: '#ff7518',
    toolboxBackgroundColour: '#F9C10E',
    toolboxForegroundColour: '#fff',
    flyoutBackgroundColour: '#252526',
    flyoutForegroundColour: '#ccc',
    flyoutOpacity: 1,
    scrollbarColour: '#ff0000',
    insertionMarkerColour: '#fff',
    insertionMarkerOpacity: 0.3,
    scrollbarOpacity: 0.4,
    cursorColour: '#d0d0d0',
    blackBackground: '#333',
  },
});
```

### Test it

If the server is already running, refresh the page to see the new changes. Otherwise, run `npm start` to start the server. You should see a themed workspace!

You may notice that the code output window looks the same. This is because the code output window is not part of the Blockly workspace. 
The code output window will remain unchanged throughout this codelab, but you are encouraged to experiment with changing this style.

<Image
  src="/images/codelabs/theme-extension/theme_components_workspace.png"
  alt="Halloween themed Blockly workspace, with unchanged code output window."
  className="codelabImage"
/>

:::tip
Try adjusting the CSS for the output pane (found in `index.css`) to match your Blockly theme!
:::

---

### Packages Docs Docs Codelabs Theme Extension Identifier Setup (`packages/docs/docs/codelabs/theme-extension-identifier/setup.mdx`)

---
description: Setting up the "Customizing your themes" codelab.
---

import Image from '@site/src/components/Image';

# Customizing your themes

## 2. Setup

This codelab will add a custom theme to the Blockly sample app.

### Create the application

Use the [`npx @blockly/create-package app`](https://www.npmjs.com/package/@blockly/create-package) command to create a standalone application that contains a sample setup of Blockly, including custom blocks and a display of the generated code and output.

1. Run `npx @blockly/create-package app custom-theme-codelab` in your terminal. This will create a Blockly application in the folder `custom-theme-codelab`.
1. Use `cd` to move into the new directory: `cd custom-theme-codelab`.
1. Run `npm start` to start the server and run the sample application.
1. The sample app will automatically run in the browser window that opens.

The local address in the address bar of your browser starting with `http://localhost:` shows where your app is.
If you accidentally close this window or tab, you can re-open this local address to view the app as long as `npm start` is still running.

### Change the storage key

Before setting up the rest of the application, **change the storage key** used for this codelab application. This will ensure that the workspace is saved in its own storage, separate from the regular sample app, so that it doesn't interfere with other demos.
In `serialization.js`, change the value of `storageKey` to some unique string. `customThemeWorkspace` will work:

```js
// Use a unique storage key for this codelab
const storageKey = 'customThemeWorkspace';
```

### Explore the starter code

Take a moment to explore the code you just created in the `custom-theme-codelab` folder. If you'd like a more in-depth explanation of all of the code in the sample app, check out the [getting started codelab](/codelabs/getting-started/codelab-overview) which goes through creating this sample app from scratch.

For a briefer outline of the code, visit the [sample app overview](/guides/get-started/sample-app-overview/) page for an overview of the included files and tooling.

### Inspect the workspace

Open the window with your running app. You should see a Blockly workspace with a code output window and a toolbox using the default theme. 

<Image
  src="/images/codelabs/theme-extension/starter_workspace.png"
  alt="The Blockly sample app with a default-themed workspace and toolbox."
  className="codelabImage"
/>

---

--- METRICS ---
- Files Extracted: 100
- Estimated Token Budget: ~67783 tokens
- Canonical Reference: https://codewiki.google/github.com/RaspberryPiFoundation/blockly
