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.
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.
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.
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:
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 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.
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 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>
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.
Previous
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.
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.