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.

Embedding applications

Check out the source code of an example embedding applications, 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 we explore more issues related to the application-block interface. We will 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.

An embedding application is any app that renders blocks conforming to this protocol, by:

  1. importing the source code for the blocks it wants to display (whether at runtime or compiled along with its own source)
  2. combining the source with the data properties the block requires (how exactly this works depends on the rendering context)
  3. rendering the block on a webpage (or other application)
  4. providing any external dependencies the block requires

The embedding application is responsible for any communication with databases and APIs required to persist and retrieve data rendered by blocks.

In order to be portable anywhere, blocks should not need to have any knowledge of the datastore the data they render comes from and is persisted to (other than in cases where blocks are designed to interact with a specific datastore or external service).

Rendering blocks

To render a block which defines a schema for the data it accepts, embedding applications MUST supply it with any data properties marked as required, SHOULD respect any other constraints expressed in the schema, and MAY supply any further properties expressed in the schema.

Embedding applications SHOULD supply blocks with functions to get, aggregate, create, delete and update entities, entity types, and links between entities (subject to any permissions restrictions).

These functions MUST conform to the naming conventions and function signatures outlined in the previous section.

Embedding applications SHOULD provide defaults for aggregation operations to handle cases where the block doesn’t specify its own requirements.

Embedding applications SHOULD provide defaults for aggregation operations to handle cases where the block doesn’t specify its own requirements (e.g. default sort, default items per response)

To enable blocks to update data of entities, including themselves, embedding applications MUST include an entityId alongside the data for each entity it supplies the block with - along with any other entity identifiers the application needs blocks to send back to it when making requests. The entityId SHOULD be unique within the application, in order for blocks to use it reliably to identify entities.

To enable blocks to properly validate user input for entities, embedding applications SHOULD include an array of schemas relevant to the data sent to the block under a entityTypes property, during instantiation and again any time new entity types are sent.

Data validation

An embedding application SHOULD be able to read a JSON schema file provided by a block describing the block’s interface, and check that the data provided to the block conform to the schema (e.g. that any validation constraints expressed by the block are respected).

Styling

Embedding applications SHOULD provide a styleVariables object passed to the block alongside other fields, containing any of the theme variables listed in Appendix A which they have a preferred value for.

Blocks SHOULD use these variables where appropriate to make their block visually consistent with the embedding application (except where applying application-supplied values may interfere with block functionality or accessibility).

Security

Naively running third-party code is inherently unsafe.

Embedding applications SHOULD take suitable precautions to ensure that block code they execute is unable to compromise their systems or their users’ data. Risk mitigation might include various approaches to sandbox block code execution.

Rendering HTML blocks inside iFrames or web workers are obvious mitigations to explore.

In these types of implementations, the embedding application would run a small application inside the iFrame or web worker. This sandbox application would in turn render the block, and provide it with the functions and data it needs.

When the block calls a function (e.g. updateEntity), the sandboxing application sends messages with the request and payload to the parent application. An example iFrame implementation can be found in HASH, a working demo for a block-embedding application.

Users COULD then be prompted to permit or deny the sort of action the block is attempting to take, and their preferences saved. The permissions a block requires could also be sought and approved in advance when a block is loaded.

Machine-readable pages

Where an embedding application supplies a block with data corresponding to structured entities, and the web page and that entity data are for public consumption, the embedding application SHOULD include machine-readable structured data on the page.

For example, JSON schema definitions for entities may include a jsonld:context key pointing to a mapping between JSON terms and IRIs, which can be used to construct a JSON-LD representation of the entity which embedding applications can include in the page's markup.

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