Using Blockly APIs

Introduction

This page describes best practices for calling functions and accessing properties in core Blockly. These principles apply to creating plugins for Blockly or to integrating Blockly into a standalone application.

Subclassing and extending

Blockly has multiple paradigms for adding functionality, including:

  • Subclasses (e.g. creating a new renderer)
  • Mixins (e.g. adding a block extension or mutator)
  • Block definitions (e.g. procedure block definitions)

For the purposes of this document, all three cases are equivalent to subclassing.

Injecting subclasses

We support replacing certain classes through the Blockly.inject method. These subclasses must either extend the base class, or implement their corresponding interface.

You can pass your subclass into the inject method.

Blockly.inject('blocklyDiv', {
  plugins: {
    'metricsManager': CustomMetricsManagerClass
  }
}

Or you can register your class using Blockly.registry and use the registry name to inject the class. This is useful if you store your injection options as pure JSON.

Blockly.registry.register(Blockly.registry.Type.METRICS_MANAGER, 'YOUR_NAME', SubClass);

Blockly.inject('blocklyDiv', {
  plugins: {
    'metricsManager': 'YOUR_NAME'
  }
}

The following classes can be replaced:

Registration Name Interface/Base Class
blockDragger Blockly.IBlockDragger
connectionChecker Blockly.IConnectionChecker
connectionPreviewer Blockly.IConnectionPreviewer
flyoutsVerticalToolbox Blockly.IFlyout
flyoutsHorizontalToolbox Blockly.IFlyout
metricsManager Blockly.IMetricsManager
renderer Blockly.blockRendering.Renderer
toolbox Blockly.IToolbox

For more information on using interfaces check the interfaces section of the documentation.

Visibility

We use TypeScript access modifiers to mark visibility in the core library as public, private, or protected. Some properties may be annotated with @internal in their TsDoc comments.

All public and protected properties are documented in the References section of the Blockly website. You can also check visibility by reading the code.

public

Anything marked public is part of our public API. Any property in a module that does not have a visibility modifier is considered public.

We try to not change our public API frequently or without good reason and warning. The exception: we may make a new API public in one release and modify it in the next release in response to early feedback. After that you may consider a public function or property stable.

Public functions may be called from anywhere, and overridden in subclasses as long as the signature does not change.

protected

Protected functions and properties may only be accessed by the defining class or a subclass.

Subclasses are allowed to override protected functions and properties, without changing type signatures.

For instance, a custom renderer that extends the base renderer class may access its protected properties.

In each case you should make sure you understand how the function or property is used in the rest of the code.

private

These can only be accessed by code in the same file as the definition. Directly accessing these properties may result in undefined behaviour.

Subclasses are not allowed to override private functions and properties.

Private properties are subject to change without warning, as they are not considered part of Blockly's public API.

Some functions in Blockly do not have visibility annotations because they are not exported from their module. These functions are essentially local variables and cannot be used outside of their defining module. They should be considered equivalent to private properties.

internal

Internal functions and properties are intended to be used within the core library, but not externally. They are designated with the TsDoc @internal annotation.

Internal properties are subject to change without warning, as they are not considered part of Blockly's public API.

Internal properties may be accessed from anywhere within core, and overridden in subclasses in core as long as the signature does not change. They must not be accessed from outside of the core library.

deprecated

Anything marked @deprecated should not be used. Most deprecations include directions on the preferred code, either in a console warning or TSDoc.

Where possible, deprecated functions will log a warning that includes the intended deletion date and a recommendation for a replacement function to call.

FAQs

What if the function I want to use isn't public?

File a feature request on core Blockly. Include a description of your use case and a statement of what you would like us to make public.

We will use the feature to request to discuss whether to make it public, or whether there are other ways for you to get the same information.

If we decide to make it public, either you or the Blockly team will make the appropriate change, and it will go live in the next Blockly release.

If you choose to use a non-public member in a plugin, consider marking your plugin as a beta and include the information in your README.

What about monkeypatching?

Read up on monkeypatching.

Monkeypatching is unsafe, because patches could stop working without notice due to using non-public pieces of the Blockly API. Patching in a plugin is especially dangerous, because your code may interact poorly with any other plugin that monkeypatches the same code. For this reason we strongly recommend against monkeypatching in applications and third party plugins, and will not accept it in first party plugins.

Can I override public functions?

When subclassing: yes. Otherwise: no, that's monkeypatching.

Can I override protected functions?

When subclassing: yes. Otherwise: no, that's monkeypatching.

Can I override internal or private functions?

No, that's monkeypatching.

When can I access properties directly? When should I use a getter or a setter?

If we publish a getter or a setter, please use that instead of directly accessing the property. If the property is not public, definitely use getters and setters.

What if a property doesn't have an annotation?

By default it's public, but please drop us a line in case we want to put a getter/setter pair in place for you.

What if a function doesn't have an annotation?

It's public by default.

What if I'm still not sure?

Ask a question on the forum and we'll get back to you, generally within a business day.