---
description: How to add a plugin field to Block Factory.
title: Add a plugin field to Block Factory
image: images/blockly_banner.png
---

# Add a plugin field to Block Factory

[Blockly Developer
Tools](https://raspberrypifoundation.github.io/blockly-samples/examples/developer-tools/index.html)
lets you create custom blocks using blocks! It has support for fields that are
published as plugins in addition to the fields that come with core Blockly. If
you've created a custom field, you can add support for it to the Block Factory
by following this guide. The custom field must be published on npm before you
can add support for it. You also need to commit to updating your field to keep
up with changes in Blockly, otherwise we may need to remove it from Block
Factory in the future.

## Development on the Block Factory

The source code for the Block Factory is located in the blockly-samples
repository in the [`examples/developer-tools`][source-developer-tools]
directory.

To submit a change to the Developer Tools in blockly-samples, you'll need to
follow the [typical steps][blockly-samples-development] for developing in
blockly-samples. Unlike working with plugins however, you'll need to run `npm
install` from the `examples/developer-tools` directory directly, rather than at
the root level of blockly-samples.

## Install the plugin

In order for the Block Factory to show your custom field in the preview, it
needs to install the custom field. Add your field as an npm dependency of
developer-tools. Then, register it or do any other setup work necessary in
[`developer-tools/src/blocks/index.ts`][source-blocks-index].

## Create a block for the field

Since the Block Factory uses blocks to create custom blocks, you'll need a block
that represents your custom field.

### Create the block definition

You need to design the block for your field; if you want to get meta, you can
even design it using Block Factory! The block should allow the user to configure
the setup required by your field, such as default values, and a name. Add this
block definition to
[`developer-tools/src/blocks/fields.ts`][source-blocks-fields], and import it in
[`developer-tools/src/blocks/index.ts`][source-blocks-index].

### Add block to toolbox

Next, you need to add this block to the toolbox definition to make it accessible
to users. The toolbox definition is located in
[`developer-tools/src/toolbox.ts`][source-toolbox]. Your block should be added
to the "Fields" category.

## Code Generators

The Block Factory works by using the Code Generator system you are already
familiar with from Blockly. Each block has a block-code generator for each type
of output generated by the Block Factory, and the parent blocks assemble the
code for the child blocks into the correct output. To add support for a custom
field, you'll need to add block-code generator functions for each of the Code
Generator classes.

Create a file for your field block in the
[`output-generators/fields`][source-output-generators] directory. You'll add the
block-code generators for each of the following Generators to this file. Import
this file in the [`blocks/index.ts`][source-blocks-index] file so that the
block-code generator functions are loaded into the application.

### JavaScript definition

The `javascriptDefinitionGenerator` creates the code that will be included in
the JavaScript definition for a block that includes your custom field. Usually,
this means the block-code generator should return a line of code that looks like
`.appendField(new YourFieldConstructor(arg1, arg2), 'userSpecifiedName')`. Note
that this line of code does _not_ include a semicolon, because an input that
contains multiple fields will have several calls to `appendField` chained
together. The arguments in the constructor are pulled from the values the user
set on the field block. Here's an example of this block-code generator for
`FieldAngle`:

```ts
javascriptDefinitionGenerator.forBlock['field_angle'] = function (
  block: Blockly.Block,
  generator: JavascriptDefinitionGenerator,
): string {
  const name = generator.quote_(block.getFieldValue('FIELDNAME'));
  const angle = block.getFieldValue('ANGLE');
  return `.appendField(new FieldAngle(${angle}), ${name})`;
};
```

The angle block that the user dragged from the "Fields" category of the Block
Factory toolbox has two fields on it:

- `FIELDNAME`: user can set the name of the field on their custom block
- `ANGLE`: user can set the default angle value

In this block-code generator, we get the default angle value and pass it as the
only argument to the `FieldAngle` constructor. The field name is always passed
as the second argument to `appendField`.

:::note
For any place you would need quotation marks around a field value, such as
when passing the name of the field to `appendField`, you should use
`generator.quote_` rather than manually wrapping in quotation marks.
:::

### JSON definition

The `jsonDefinitionGenerator` is similar, but this outputs the part of the JSON
block definition that corresponds to your field. Typically, this code is a JSON
object that includes:

- `type`: corresponds to the name of your field in the Blockly field registry
- `name`: user can set the name of the field on their custom block
- any other custom properties needed by your field's json initialization
  method.

Here's an example from the `FieldAngle` again:

```ts
jsonDefinitionGenerator.forBlock['field_angle'] = function (
  block: Blockly.Block,
  generator: JsonDefinitionGenerator,
): string {
  const code = {
    type: 'field_angle',
    name: block.getFieldValue('FIELDNAME'),
    angle: block.getFieldValue('ANGLE'),
  };
  return JSON.stringify(code);
};
```

:::note
Block-code generators always return strings, so stringify the object
before returning it.
:::

### Code headers

The Code Header Generator creates the Code Headers output shown in the Block
Factory. This output can be toggled between esmodule imports and script tags,
depending on how the user wishes to load the code, so there are actually two
different generator instances: one for each case. You need to add a block-code
generator for each of them. Here's an example for `FieldAngle`:

```ts
importHeaderGenerator.forBlock['field_angle'] = function (
  block: Blockly.Block,
  generator: CodeHeaderGenerator,
): string {
  generator.addHeaderLine(
    `import {registerFieldAngle, FieldAngle} from '@blockly/field-angle';`,
  );
  generator.addHeaderLine(`registerFieldAngle();`);
  return '';
};

scriptHeaderGenerator.forBlock['field_angle'] = function (
  block: Blockly.Block,
  generator: CodeHeaderGenerator,
): string {
  generator.addHeaderLine(
    `<script src="https://unpkg.com/@blockly/field-angle"></script>`,
  );
  generator.addHeaderLine(`registerFieldAngle();`);
  return '';
};
```

These generators have a method called `addHeaderLine` that lets you specify a
line of code that should be called before your field is used in code. Commonly,
this includes work such as importing the field or loading it through a script
tag, and perhaps calling a function that will register the field with Blockly's
field registry.

:::tip
If your package is published on npm, it should automatically be available
on unpkg, which is a convenient place that script tags can load from.
:::

For these two block-code generators, all the code should be added through calls
to `addHeaderLine`. This function will ensure each header line is only shown
once, even if your custom field block is used multiple times in one custom
block. The block-code generator should return the empty string.

### Generator stub

Lastly, we have the generator that creates the generator stub for the field. In
this block-code generator, you'll be writing code that generates code that helps
the user write code that generates code. Confused yet? It's easier than it
sounds!

The generator stub for a custom block includes a premade variable
representing every field on the block. Then there's a `TODO` the user must
finish to assemble all of these variables into the final code string their
custom block will return. That means typically all your block-code generator
needs to do is return the line that creates this custom variable. Say the user
is making a custom block that will add rays of sunlight to their canvas. They
add an angle field to the block and name it `"SUN_DIRECTION"`. The generator
stub for this block would include the line `const angle_sun_direction =
block.getFieldValue("SUN_DIRECTION");`. That is the line of code our block-code
generator for the angle field needs to return:

```ts
generatorStubGenerator.forBlock['field_angle'] = function (
  block: Blockly.Block,
  generator: GeneratorStubGenerator,
): string {
  const name = block.getFieldValue('FIELDNAME');
  const fieldVar = generator.createVariableName('angle', name);
  return `const ${fieldVar} = block.getFieldValue(${generator.quote_(
    name,
  )});\n`;
};
```

To get a standardized name for the variable, you can call
`generator.createVariableName` and pass in the type of your field (such as
`angle`, `number`, etc.) along with what the user named their field.

## Test it

After you've written all of these pieces, you should be able to start the Block
Factory by running `npm start` in the `blockly-samples/examples/developer-tools`
directory. You should be able to drag your block from the field category, add it
to an input on a block, and watch the output change. Check that the preview of
the block looks right, and that the code for each of the output sections is
correct.

[blockly-samples-development]: /guides/contribute/samples
[source-developer-tools]: https://github.com/RaspberryPiFoundation/blockly-samples/blob/main/examples/developer-tools
[source-blocks-index]: https://github.com/RaspberryPiFoundation/blockly-samples/blob/main/examples/developer-tools/src/blocks/index.ts
[source-blocks-fields]: https://github.com/RaspberryPiFoundation/blockly-samples/blob/main/examples/developer-tools/src/blocks/fields.ts
[source-toolbox]: https://github.com/RaspberryPiFoundation/blockly-samples/blob/main/examples/developer-tools/src/toolbox.ts
[source-output-generators]: https://github.com/RaspberryPiFoundation/blockly-samples/tree/main/examples/developer-tools/src/output-generators/fields
