Specification

The open-source protocol for creating interactive, data-driven blocks

This document is a working draft

This specification is currently in progress. We’re drafting it in public to gather feedback and improve the final document. If you have any suggestions or improvements you would like to add, or questions you would like to ask, feel free to submit a PR or open a discussion on our GitHub repo.

Implementation approaches

This section is guidance which forms part of explanatory material rather than the specification itself.

It is included in this draft to aid the reader in understanding the full context, but will be published outside the spec in its final form.

Validating compliance

When publishing the block protocol, we will provide tooling to help validate block type compliance with the block protocol. We may wish to dictate that blocks meet certain standards before they are made available via the Block Hub.

Rendering contexts

We have published the source code of an example embedding application, HASH.

This is a work-in-progress environment we are using to explore and test assumptions and suggested approaches in the Block Protocol.

As we develop this application further, we will test various rendering strategies in it, and provide abstractions for embedding applications to minimize the amount of work required to use blocks.

We welcome feedback and suggestions - please open or contribute to a discussion to do so.

The protocol specifies an interface between blocks and embedding applications, defining how data is referred to when it is communicated between the two, but it leaves open:

  • the particular implementation and composition of block source code

  • how exactly data is transferred between an application and a block

  • how exactly blocks are rendered (and re-rendered) by applications

There are various different implementations of embedding applications and blocks which would be compliant with the protocol, but not with one another.

The ultimate goal of the Block Protocol and supporting ecosystem is that any embedding application should be able to render any block, if both are correctly configured.

In order to achieve this, embedding applications will need to have strategies for handling blocks which are implemented in different ways.

For example:

  • a block implemented as a React component would require an embedding application to render the block to the DOM using React, and pass the data and functions it expects as its "props"
  • in a block with an HTML entrypoint, appropriately sandboxed by the embedding application, the properties could be in the global scope of the sandbox (with the block assuming they are available)

There must be some way of applications identifying how each block should be rendered. This might be achieved via inference from the block's source (e.g. the extension of its entrypoint), or by an explicit property in a block's metadata file. Either approach will require a small number of known, agreed 'block implementation approaches' which can be identified and handled.

Examples in more detail:

React

React lends itself well to block authoring and embedding, given its principles of composable, reusable components.

  • A block authored in React should express its schema in line with the props of its entrypoint component, e.g. AppProps.

  • Blocks should be transpiled to ES5-compliant code with a commonjs module target, with the entrypoint source file of the component’s main JavaScript file: this allows embedding applications to render the component function in their main component tree and provide it with the imports it requires (by providing the commonjs requires function).

  • Block authors should expect the required properties expressed in their schema passed into the component as props, alongside (possibly) the special block protocol functions, and (possibly) any properties not marked as required.

  • Blocks authored in React should specify React as an external library, i.e. do not bundle React with their package, as the embedding application can provide it as described above via a special requires, saving on bundle size.

HTML

A plain HTML block – i.e. a block that has an HTML entry point, and does not rely on the embedding application running a particular web rendering framework/library – is a valid block.

If it has no data interface requirements, it need not be accompanied by a schema in its package.

Like any block, plain HTML blocks should be sandboxed, but particularly given that any JavaScript they load cannot otherwise be scoped to them in the way that a React component’s can.

By sandboxing HTML blocks, e.g. in an iFrame, any data, functions and properties they provide could be declared in the scope of the sandbox.

One alternative to functions for blocks requesting action is to use is to define custom DOM events which are dispatched from blocks and listened for by embedding applications, inside the sandbox.

Web Components

Web Components are one way in which a Block Protocol block might be implemented, with the addition of a schema expressing the properties the component expects (if any).

The component might expect data to be supplied as attributes (e.g. text in <custom-elem text="test" />).

Rendering blocks with a Web Component entry point might involve special handling - they are defined with specific names in their source, which have to be used when instantiating them, e.g. <custom-elem>

  • the embedding application could know about Web Components and take a special approach to rendering and supplying them with data – in which case there would need to be a way of programmatically indicating in the block’s metadata that it was a Web Component, and its name, or
  • block authors could provide a wrapper around the Web Component which dealt with rendering it, exposing the block to embedding applications via some other strategy such as an HTML entry point.
  • where Web Components dispatch events as a means of passing data to their embedder, they would need to be updated to use the defined BP function names, or at least have a wrapper which listened for their specific events and called the appropriate BP function (or dispatched the appropriately-named BP event).

Templating languages

Blocks written in templating languages can reference their expected data properties in the template.

This offers a solution for versions of blocks authored for Ruby on Rails or Django web servers, for example.

Add blocks to your app

Anyone with an existing application who wants to embed semantically-rich, reusable blocks in their product can use the protocol. Improve your app’s utility and tap into a world of structured data with no extra effort, for free.

Read the Embedding Guide

Build your own blocks

Any developer can build and publish blocks to the global registry for other developers to use. Create blocks that solve real-world problems, and contribute to an open source community changing the landscape of interoperable data.

Read the Quickstart Guide