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.

RFCs & Roadmap

New services

We will introduce the following new services to the Block Protocol to support additional functionality that requires application-block cooperation.

We welcome suggestions for other services that may be useful, via GitHub discussions or by creating RFCs.

Actions

A generalized approach to capturing user actions could involve a service whereby a block reports on which elements within it capture actions (e.g. a button), and embedding applications could choose to bind further actions to them as a response.

Comments

We want to facilitate users leaving comments on elements within blocks. This could be

  • managed entirely outside the block, e.g. by a wrapper around the block which provides a context menu to users for adding comments on blocks – which avoids blocks having to have any knowledge of commenting, but could interfere with how the block wants to respond to user input, or
  • managed by providing a new service whereby blocks could send messages requesting that comments be attached to specific elements in blocks – which allows blocks to have control over how and to what element the user is able to attach comments.

Internationalization

A service to provide the user’s preferred locale to blocks. Please see the GitHub discussion.

Location

A service to provide the user’s location to blocks (with appropriate safeguarding).

Styling

The styling service would involve the embedding application to communicate styling or theming data to blocks, to allow blocks to apply styling to make them appear more visually consistent with the application embedding them.

Please see the GitHub discussion for a discussion of what data might be transported as part of a styling service (e.g. a styleObject, or a CSS file).

Hook

There will be a hook service, which will act as an escape hatch for embedding applications to ‘reach into’ blocks to directly render content, or to manipulate content rendered by the block . This will rely on cooperation from the block author.

Users

Much familiar functionality requires a reference to the current user, or being able to select from users in the system. For example:

  • reacting to a post (linking the current user to the post via a reaction)
  • assigning a user to an action item (linking the current user to the action item)
  • searching for users to mention (having user display names to select from and search)

A users service could help expose some of this data to blocks, with appropriate safeguarding and permissions sought.

Versioning

While embedding applications can handle displaying an interface for reloading blocks at particular earlier versions, we will specify a way of communicating to blocks that (a) an earlier version is being displayed, and (b) the difference with the current version would allow blocks to implement visual diffs.

Changes to existing services

Core

Block definition
Self-contained blocks and sandboxing

At the moment, the specification is largely silent on sandboxing, and blocks should be designed to work whether in their own scope or in the scope of a wider application, e.g. by not polluting the global scope.

We also considered having two distinct types of block, with different rendering and message transport requirements, with the second type being self-contained blocks designed to be loaded into an iframe directly. This would make it simpler to write particular types of blocks, as they would not need to load their own internal iFrame in order to use a specific origin or to own their scope:

  1. Components (current approach):
  • elements rather than more complex, typically with a JavaScript entry point (though can also be HTML files which load their own scripts)
  • designed so that they can share their scope with other components, without interfering with JavaScript, styles, etc
  • require their source to be incorporated as part of a wider page by the embedding application (which may be sandboxed or not)
  • require the embedding application knowing how to render them, depending on how the block is defined
  • send messages to the embedding application by dispatching a CustomEvent
  • may specify externals – libraries they depend on but expect the embedding application to make available in their scope.
  1. Self-contained block (addition or alternative):
  • must have an HTML entry point and be designed to be loaded directly into an iFrame
  • must be sandboxed by the embedding application
  • are designed to not share their scope with any other code or styling
  • rely on communication via messages sent via and listened for in the global scope, via postMessage
  • include every library they depend on within their block package

We seek views on whether we should introduce "self-contained" blocks either as an alternative to the current component blocks, or instead of them.

Adding self-contained blocks as an alternative would provide better first-class support in the specification for blocks which wish to be guaranteed their own scope or origin, at the expense of introducing more complexity to the specification in order to handle two types of blocks.

Making self-contained blocks the only type of block would eliminate a class of problems related to blocks sharing a scope with other code, by virtue of and at the expense of requiring all blocks to be sandboxed, which may impact performance for applications that would otherwise leave trusted blocks un-sandboxed.

Having no self-contained blocks (the current position) makes it more cumbersome to write blocks that own a scope or use a specific origin, as they must load their own iFrame to do so. Writing HTML blocks also involves additional steps for both the embedding application and block author, in order for the block to be able to identify itself.

Component entry point

Even within block definition as currently specified (described above as the component type), we allow that blocks may be defined in different ways, with an entry point specified by the type in their metadata. For example, a HTML file, React component, or custom element (Web Component).

We might alternative specify a single valid entry point for blocks, in order that embedding applications do not have to deal with different rendering strategies.

We believe a single valid entry point should be a native web technology. This implies either:

  • an HTML file, which loads its own scripts which can then call other libraries and technologies as required
  • a custom element class, which can call other libraries and technologies as required within its constructor

This would reduce the burden on embedding applications imposed by having multiple possible block definitions, at the expense of the entry for blocks be written in a particular way. It would also introduce some indirection where application and blocks would otherwise use the same technology (e.g. a React application that renders only React blocks would now do so via some other intervening entry point).

Service permissions / requirements

Applications may implement some services only, or implement part of a service only (e.g. allowing createEntity but not createEntityType).

Many blocks will require certain services, and parts of services.

Blocks will not work in applications that do not implement the services they require, and the parts of services they require. If there is a mismatch which is not identified prior to a block being selected for use, they may crash or be non-functional at the point of use.

Proposal

In order to predict in advance whether a given block will work in a given application, it would be helpful for blocks to be able to indicate which services and parts of services they require.

The most detailed version of this would be for blocks to be able to:

  • express requirements/support at a service level (e.g. requires: "graph"), and
  • express finer-grained detail, e.g.
    • which specific messages from a service they require/support
    • any additional detail on what they require from a message, which might be a particular scope, e.g. access to retrieve or create particular types of entities.

Graph

Entity types

We’re intending to move away from entities having to fully describe the constraints of each of their properties. Instead, type definitions are going to become shareable and reusable in a new type system which establishes a hierarchy of types to address a number of shortcomings in our current system. For in-depth motivation, a proposed implementation plan, and the wide-reaching implications please see the RFC.

Pagination

We intend to move to a cursor-based method for paginating aggregations of entities, likely based on the Connections specification.

Schema mapping

The Block Protocol does not seek to describe or prescribe the shape of particular entities (e.g. what fields a Person has).

Instead, it seeks to define the block-application interface.

This does, however, mean there is a possibility of competing schemas attempting to describe the same entities, which different blocks using different schema - reducing the portability of blocks.

The ability to translate between schemas would help - e.g. some way expressing an equivalence relationship between properties in different schema. This might be a keyword such as sameAs or equivalentTo mapping between schemas and their properties. Then, either blocks or embedding applications could programmatically translate between schemas.

Note that this is about translating between different JSON Schemas, and is not to be confused with the process of translating JSON schema to schema.org (and equivalent) types, which has an established technical approach mentioned here.

We're hiring full-stack TypeScript/React and PHP plugin developers to help grow theBlock ProtocolWordPress ecosystem.Learn more