BlockSpec Open Standard BETA
BlockSpec
v0.1.0

A single source of truth for content blocks

BlockSpec is an open standard for defining a content block as structured, machine-readable JSON. The HTML contract, content fields, layout variants, design tokens, and authoring guidance — all in one canonical file.

BlockSpec describes a single block as a complete unit: how it renders, what content it accepts, which design tokens it consumes, and how to fill it in well. One spec replaces the gap between design system, CMS schema, and authoring documentation.

The problem it solves

Component libraries describe how blocks look. CMS field schemas describe what blocks contain. Design tokens describe how they're styled. Authoring guidance lives in a Notion doc someone wrote a year ago.

Every layer is owned by a different tool, drifts from the others, and gets rebuilt from scratch on every project.

What it replaces

  • Separate Figma component definitions
  • ACF or Gutenberg field schemas drifting from design
  • Verbal handoffs between designers and developers
  • "What goes in this slot?" emails to clients
  • Manual rebuilds of the same Hero in every project

A BlockSpec file is a single .json document describing one block. A library is a collection of BlockSpec files — one per block — composable into pages by StructureSpec.

  1. Define the block

    Create a blockspec.json file using the open schema. Specify the HTML contract — data-block slug, allowed surfaces and layouts, structural pattern — alongside content fields, variants, token roles consumed, and authoring guidance.

  2. Compose pages with StructureSpec

    StructureSpec references BlockSpec items by slug to compose page archetypes. A "Marketing landing page" type might list Hero, Feature grid, Testimonial, and CTA in sequence — each one a separate BlockSpec file in the library.

  3. Render with brand tokens

    A consumer reads the block's HTML contract from BlockSpec and the visual styling from a parent BrandSpec. The same block renders consistently across projects, themed by token swap rather than restyled by hand.

  4. Author with guidance

    Field-level prompts, character limits, and voice guidance turn a blank CMS form into a guided framework. The block tells the author what's expected, in what order, with what tone — and AI tools can use the same guidance to draft content directly.

For AI tools: BlockSpec gives content-generating models a structured slot specification. Instead of inferring what a Hero needs, the model receives a typed schema — required fields, character limits, voice guidance — and produces output that fits the block precisely.

A BlockSpec document is a JSON object with a root block key and seven top-level sections. All sections are optional at the object level but recommended for complete block definition. Identity and contract are the minimum viable spec.

block.identity

Block name, slug, category, description, and version. The slug is the canonical identifier used by StructureSpec and CMS integrations to reference this block.

name slug category version

block.contract

The DOM contract. The data-block attribute value, allowed data-surface values, allowed data-layout values, structural pattern, and breakpoint policy.

dataBlock surfaces[] layouts[] structure

block.fields

Content fields the block accepts. Each field defines a name, type, label, help text, required flag, and validation constraints such as character limits or allowed values.

name type required characterLimit

block.variants

Layout variants of the same block. A Hero might have centered, split, media-right variants — each declares which fields it uses and which layout attribute it maps to.

name description fieldsUsed[] layout

block.tokens

Design-token roles the block consumes. References roles (primary, heading, section-spacing) rather than values, so the block can be themed by any compatible BrandSpec.

colors[] typography[] spacing[]

block.guidance

Voice guidance and field-level prompts. Authoring help for humans; structured scaffolding for AI tools. The guidance layer turns a generic block into a guided form.

voice fieldPrompts examples

block.metadata

Administrative fields: block name, version string, last updated timestamp, and tags. Used for versioning, auditing, and tool compatibility checks.

name version lastUpdated tags[]

Field definition fields

Field Type Description Example
name string Field slug — used as the key when content is stored "headline"
label string Human-readable label shown in the authoring UI "Headline"
type string Field type: text, rich-text, link, media, number, select, repeater "text"
required boolean Whether the field must be populated for the block to render true
characterLimit integer Maximum character count (text and rich-text fields) 80
help string Inline help text shown to the author beside the field "The single sentence that earns attention."

Contract fields

The contract object defines the HTML/DOM shape every instance of this block must conform to. It is the public interface that consuming tools render against.

Field Type Description Example
dataBlock string Value of the data-block attribute on the root element "hero"
structure string The DOM nesting pattern (selector-style) "section[data-block=hero] > .container > .inner"
surfaces string[] Allowed values for the data-surface attribute ["default", "muted", "inverse"]
layouts string[] Allowed values for the data-layout attribute ["centered", "split"]
scopedCss boolean Whether the block ships with scoped CSS (BEM or attribute-scoped) true
breakpointPolicy string Responsive policy: fluid, single-breakpoint, multi-breakpoint "fluid"

A complete BlockSpec document for a Hero block. All fields shown are part of the v0.1.0 schema.

{
  "_export": {
    "blockName":        "Hero",
    "blockSpecVersion": "0.1.0",
    "exportedAt":       "2026-05-02T10:00:00.000Z"
  },

  "block": {

    /* ── Identity ────────────────────────────── */
    "identity": {
      "name":        "Hero",
      "slug":        "hero",
      "category":    "lead",
      "description": "Page-opening section with headline, supporting copy, and CTAs.",
      "version":     "1.0.0"
    },

    /* ── Contract ────────────────────────────── */
    "contract": {
      "dataBlock":        "hero",
      "structure":        "section[data-block=hero][data-surface][data-layout] > .container > .inner",
      "surfaces":         ["default", "muted", "inverse", "accent"],
      "layouts":          ["centered", "split", "media-right", "media-left"],
      "scopedCss":        true,
      "breakpointPolicy": "fluid"
    },

    /* ── Fields ──────────────────────────────── */
    "fields": [
      {
        "name":           "headline",
        "label":          "Headline",
        "type":           "text",
        "required":       true,
        "characterLimit": 80,
        "help":           "The single sentence that earns attention."
      },
      {
        "name":           "subhead",
        "label":          "Supporting copy",
        "type":           "rich-text",
        "required":       false,
        "characterLimit": 240,
        "help":           "One or two sentences expanding on the headline."
      },
      {
        "name":     "primaryCta",
        "label":    "Primary CTA",
        "type":     "link",
        "required": false,
        "help":     "The primary action you want people to take."
      },
      {
        "name":     "media",
        "label":    "Hero image or video",
        "type":     "media",
        "required": false,
        "help":     "Used in split, media-right, and media-left layouts."
      }
    ],

    /* ── Variants ────────────────────────────── */
    "variants": [
      {
        "name":        "centered",
        "layout":     "centered",
        "description": "Headline and copy centered above CTAs. No media.",
        "fieldsUsed":  ["headline", "subhead", "primaryCta"]
      },
      {
        "name":        "split",
        "layout":     "split",
        "description": "Headline left, media right, 50/50 split.",
        "fieldsUsed":  ["headline", "subhead", "primaryCta", "media"]
      }
    ],

    /* ── Tokens consumed ─────────────────────── */
    "tokens": {
      "colors":     ["primary", "neutral", "accent"],
      "typography": ["heading", "body"],
      "spacing":    ["section", "stack-md"]
    },

    /* ── Guidance ────────────────────────────── */
    "guidance": {
      "voice": "Clear and direct. Earn attention with specificity.",
      "fieldPrompts": {
        "headline":   "The single sentence that captures what this page is about. Choose clear over clever.",
        "subhead":    "One or two sentences expanding on the headline with the why or the how.",
        "primaryCta": "The verb is more important than the adjective. 'Start now' beats 'Get amazing access'."
      }
    },

    /* ── Metadata ────────────────────────────── */
    "metadata": {
      "name":        "Hero",
      "version":     "1.0.0",
      "lastUpdated": "2026-05-02T00:00:00.000Z"
    }

  },

  "$schema":  "https://blockspec.org/schema/v0.1/blockspec.json",
  "version":  "0.1.0"
}

BlockSpec is designed to be consumed by any tool that needs a structured block definition — page renderers, CMS field generators, AI authoring tools, design-system documentation. Below are reference patterns for the most common outputs.

Render the HTML contract

Read the contract from BlockSpec and emit the canonical DOM structure. Surface and layout are passed in as attributes; field content fills the inner template.

/* Generated from blockspec.json → block.contract */
<section data-block="hero" data-surface="default" data-layout="centered">
  <div class="container">
    <div class="inner">
      <h1>{{ headline }}</h1>
      <p>{{ subhead }}</p>
      <a href="{{ primaryCta.href }}">{{ primaryCta.label }}</a>
    </div>
  </div>
</section>

Generate a CMS field schema

Map BlockSpec fields directly to ACF field groups, Gutenberg block attributes, or any other CMS field schema. The block becomes a guided form, not a blank page.

// Generate ACF field group from BlockSpec
const spec = await fetch('/blocks/hero/blockspec.json').then(r => r.json());

const acfFields = spec.block.fields.map(field => ({
  key:          `field_${field.name}`,
  label:        field.label,
  name:         field.name,
  type:         mapType(field.type),     // 'text' → 'text'; 'rich-text' → 'wysiwyg'
  required:     field.required,
  maxlength:    field.characterLimit,
  instructions: field.help
}));

AI-assisted authoring

Combine BlockSpec field guidance with PersonSpec or BrandSpec voice to generate calibrated draft content. The block defines what's needed; the brand or person defines how it should sound.

// Draft Hero content from BlockSpec + BrandSpec voice
const block = await fetch('/blocks/hero/blockspec.json').then(r => r.json());
const brand = await fetch('/brandspec.json').then(r => r.json());

const draftPrompt = `
  Block: ${block.block.identity.name}
  Voice guidance: ${block.block.guidance.voice}
  Brand tone: ${brand.brand.voice.tone.join(', ')}

  Generate content for these fields:
  ${block.block.fields.map(f =>
    `- ${f.label} (max ${f.characterLimit} chars): ${block.block.guidance.fieldPrompts[f.name]}`
  ).join('\n')}
`;

Composition with StructureSpec: StructureSpec page archetypes reference BlockSpec items by slug. A "Marketing landing page" archetype lists hero → feature-grid → testimonial → cta in sequence; the renderer pulls each BlockSpec to lay them out, then fills them with content from the CMS.

BlockSpec is designed to be standards-aware. It builds on, references, and is interoperable with several established frameworks. It is not a replacement for any of them — it is a structured layer that makes them composable in a single, machine-readable file.

BrandSpec

The sibling open standard for organisational brand definitions. BlockSpec consumes BrandSpec tokens by role — when a block declares it consumes the primary colour role and heading typography role, those values come from the BrandSpec applied at render time.

brandspec.org tokens roles

StructureSpec

The sibling open standard for page structure. StructureSpec consumes BlockSpec — page archetypes reference blocks by slug to compose sequences. BlockSpec describes the parts; StructureSpec describes the wholes.

structurespec.org composition archetypes

JSON Schema

The BlockSpec document format is defined using JSON Schema (Draft 2020-12). The $schema field in every BlockSpec file points to the published schema, enabling validation in any compatible tool. Editors such as VS Code will auto-complete and validate a BlockSpec file when the schema URI is present.

json-schema.org Draft 2020-12 Validation

HTML5 & data attributes

The BlockSpec contract is HTML-native. Blocks render as standard semantic elements with data-* attributes for surface and layout — not custom elements, not framework-specific components. Any rendering environment that understands HTML can consume a BlockSpec.

HTML5 data-* semantic

BEM & scoped CSS

BlockSpec's scopedCss declaration follows BEM conventions or attribute-scoped equivalents. Styles attach to [data-block=name] selectors, ensuring blocks ship with their own CSS that doesn't leak into the surrounding cascade.

BEM scoped isolation

WAI-ARIA

BlockSpec contracts are accessibility-aware by default. Each block declares the semantic landmark it represents and inherits ARIA conventions from the underlying HTML elements rather than reimplementing them.

w3.org ARIA accessibility

Relationship to StructureSpec: BlockSpec and StructureSpec are designed as a pair. BlockSpec defines individual blocks as complete units (contract + fields + guidance). StructureSpec composes them into page archetypes. Together they replace what design-system tools, CMS field schemas, and authoring documentation each cover separately.