Source code

Revision control

Copy as Markdown

Other Tools

[
{
"$id": "page",
"title": "Generated page",
"description": "A composed page: an optional header, an ordered array of body blocks, and an optional footer. Body blocks are six families (text / table / cards / list / timeline / highlight), each self-identifying via `type` and choosing a `layout`. Rendered with the Mozilla design-token system (light).",
"type": "object",
"required": ["blocks"],
"additionalProperties": false,
"properties": {
"version": {
"type": "string",
"description": "Optional schema/version tag, e.g. \"2\"."
},
"header": { "$ref": "header" },
"blocks": {
"type": "array",
"description": "Ordered body content. Each item is discriminated by its `type`.",
"items": {
"oneOf": [
{ "$ref": "text" },
{ "$ref": "table" },
{ "$ref": "cards" },
{ "$ref": "list" },
{ "$ref": "timeline" },
{ "$ref": "highlight" }
]
}
},
"footer": { "$ref": "footer" }
},
"examples": [
{
"version": "2",
"header": {
"type": "header",
"eyebrow": "From your open tabs",
"icon": "🏨",
"title": "Places to Stay on Niijima",
"subhead": "Three saved listings, compared"
},
"blocks": [
{
"type": "highlight",
"layout": "full-width",
"eyebrow": "The short answer",
"title": "Yado Marubun is the pick unless price is the deciding factor.",
"body": "Best-reviewed and closest to the port; $106/night more than the cheapest."
},
{
"type": "table",
"layout": "ranked",
"title": "Hotel Comparison",
"description": "The best options gathered from your open tabs",
"itemType": "Hotel",
"fields": [
{
"key": "name",
"label": "Name",
"type": "text",
"role": "title",
"property": "name"
},
{
"key": "source",
"label": "",
"type": "text",
"role": "subtitle"
},
{
"key": "price",
"label": "Price",
"type": "currency",
"role": "detail",
"sortable": true,
"suffix": " / night",
"property": "offers.price",
"goal": "min"
},
{
"key": "rating",
"label": "Rating",
"type": "rating",
"role": "detail",
"sortable": true,
"max": 5,
"property": "aggregateRating.ratingValue",
"goal": "max"
},
{
"key": "url",
"label": "Open",
"type": "url",
"role": "action",
"property": "url"
}
],
"data": [
{
"name": "Nijima Escape",
"source": "airbnb.com",
"price": 109,
"rating": 3.9,
},
{
"name": "Yado Marubun",
"source": "expedia.com",
"price": 215,
"rating": 4.9,
}
]
}
],
"footer": {
"type": "footer",
"text": "Keep it going",
"buttons": [
{ "text": "Turn this into cards", "href": "app://views/relayout" },
{ "text": "Add a block", "href": "app://views/add" }
]
}
}
]
},
{
"$id": "header",
"title": "Header block",
"description": "Page hero: an optional uppercase eyebrow/kicker, an optional emoji icon, a title, and an optional subhead.",
"type": "object",
"required": ["type", "title"],
"additionalProperties": false,
"properties": {
"type": { "const": "header", "description": "Block discriminator." },
"eyebrow": {
"type": "string",
"description": "Small uppercase kicker above the title, e.g. \"From your open tabs\"."
},
"icon": {
"type": "string",
"description": "Optional single emoji shown with the title.",
"maxLength": 8
},
"title": {
"type": "string",
"description": "Main page title (rendered in the condensed display face).",
"minLength": 1
},
"subhead": {
"type": "string",
"description": "Optional supporting line beneath the title."
}
},
"examples": [
{
"type": "header",
"eyebrow": "Content blocks · Exploration",
"icon": "🏨",
"title": "Hotels in Lisbon",
"subhead": "4 options gathered from your open tabs"
}
]
},
{
"$id": "footer",
"title": "Footer block",
"description": "Follow-up actions rendered as pill chips. Each points at an external URL or an in-app route/action id.",
"type": "object",
"required": ["type", "buttons"],
"additionalProperties": false,
"properties": {
"type": { "const": "footer", "description": "Block discriminator." },
"text": {
"type": "string",
"description": "Optional heading above the chips, e.g. \"Keep it going\"."
},
"buttons": {
"type": "array",
"description": "1 to 4 follow-up actions.",
"minItems": 1,
"maxItems": 4,
"items": {
"type": "object",
"required": ["text", "href"],
"additionalProperties": false,
"properties": {
"text": {
"type": "string",
"minLength": 1,
"description": "Chip label."
},
"href": {
"type": "string",
"format": "uri-reference",
"description": "External URL or in-app route/action id."
},
"variant": {
"enum": ["primary", "secondary"],
"default": "secondary",
"description": "Visual weight."
}
}
}
}
},
"examples": [
{
"type": "footer",
"text": "Keep it going",
"buttons": [
{
"text": "Try another layout for this block",
},
{
"text": "Turn this into a table instead",
"href": "app://views/table"
},
{ "text": "Add a block to this page", "href": "app://views/add" }
]
}
]
},
{
"$id": "text",
"title": "Text block",
"description": "Plain writing — a summary, an explanation, a side-titled passage, or a quote. Fields used depend on `layout`.",
"type": "object",
"required": ["type", "layout"],
"additionalProperties": false,
"anyOf": [
{ "required": ["lead"] },
{ "required": ["paragraphs"] },
{ "required": ["sections"] },
{ "required": ["quote"] }
],
"properties": {
"type": { "const": "text" },
"layout": {
"description": "summary = lead sentence + paragraphs; subheads = named `sections`; side-title = `title` in a left column + paragraphs; quote = pulled `quote` + `attribution`.",
"enum": ["summary", "subheads", "side-title", "quote"]
},
"title": {
"type": "string",
"description": "Heading (left column for side-title; small caption elsewhere)."
},
"subtitle": {
"type": "string",
"description": "Optional caption under the title (side-title layout)."
},
"lead": {
"type": "string",
"description": "Larger lead sentence (summary layout)."
},
"paragraphs": {
"type": "array",
"items": { "type": "string" },
"description": "Body paragraphs."
},
"sections": {
"type": "array",
"description": "Named sub-sections (subheads layout).",
"items": {
"type": "object",
"required": ["heading", "body"],
"additionalProperties": false,
"properties": {
"heading": { "type": "string" },
"body": { "type": "string" }
}
}
},
"quote": {
"type": "string",
"description": "Pulled quotation (quote layout)."
},
"attribution": {
"type": "string",
"description": "Who/what the quote is from."
}
},
"examples": [
{
"type": "text",
"layout": "subheads",
"sections": [
{
"heading": "How cold is too cold",
"body": "Rated output holds to roughly 5°F on qualifying models."
},
{
"heading": "What it costs to run",
"body": "Every estimate depends on the local electric-to-gas price ratio."
}
]
}
]
},
{
"$id": "table",
"title": "Table block",
"description": "Structured comparison. Record layouts (ranked / thumbnail / grouped / side-title) use `fields` + `data`; `matrix` transposes to `columns` + `rows` with a per-row winner; `key-value` uses `pairs`.",
"type": "object",
"required": ["type", "layout"],
"additionalProperties": false,
"anyOf": [
{ "required": ["fields", "data"] },
{ "required": ["columns", "rows"] },
{ "required": ["pairs"] }
],
"properties": {
"type": { "const": "table" },
"layout": {
"enum": [
"ranked",
"matrix",
"grouped",
"key-value",
"side-title",
"thumbnail"
]
},
"title": { "type": "string" },
"description": { "type": "string" },
"itemType": {
"type": "string",
"description": "schema.org type of each row (record layouts), for JSON-LD."
},
"fields": {
"type": "array",
"minItems": 1,
"items": { "$ref": "field" },
"description": "Column definitions (record layouts)."
},
"data": {
"type": "array",
"items": { "type": "object" },
"description": "One object per row."
},
"groupBy": {
"type": "string",
"description": "For `grouped`: the data key whose value names each group (shown once on the left)."
},
"pairs": {
"type": "array",
"description": "For `key-value`: a single subject's facts.",
"items": {
"type": "object",
"required": ["label", "value"],
"additionalProperties": false,
"properties": {
"label": { "type": "string" },
"value": { "type": "string" }
}
}
},
"columns": {
"type": "array",
"description": "For `matrix`: the things being compared (each a column).",
"items": {
"type": "object",
"required": ["name"],
"additionalProperties": false,
"properties": {
"name": { "type": "string" },
"label": {
"type": "string",
"description": "Superlative eyebrow, e.g. \"Best value\"."
}
}
}
},
"rows": {
"type": "array",
"description": "For `matrix`: one attribute per row; cells align to `columns`.",
"items": {
"type": "object",
"required": ["label", "cells"],
"additionalProperties": false,
"properties": {
"label": {
"type": "string",
"description": "Attribute name (left)."
},
"cells": {
"type": "array",
"items": {
"type": "object",
"required": ["value"],
"additionalProperties": false,
"properties": {
"value": { "type": "string" },
"winner": {
"type": "boolean",
"description": "Accent this cell as the best in the row.",
"default": false
},
"note": {
"type": "string",
"description": "Winner pill, e.g. \"+6 hrs\" or \"Lower\"."
}
}
}
}
}
}
}
},
"examples": [
{
"type": "table",
"layout": "key-value",
"title": "Ferry Details",
"pairs": [
{ "label": "Ferry crossing", "value": "8 hr 30 min" },
{ "label": "Operator", "value": "Tokai Kisen" },
{ "label": "One-way fare", "value": "¥8,400" }
]
}
]
},
{
"$id": "cards",
"title": "Cards block",
"description": "Blocks with images or a link out. `picks` = superlative grid; `wide-detail` = image + specs; `source-tiles` = the tabs themselves (no image); `centered` = big centered title over a grid.",
"type": "object",
"required": ["type", "layout", "items"],
"additionalProperties": false,
"properties": {
"type": { "const": "cards" },
"layout": {
"enum": ["picks", "wide-detail", "source-tiles", "centered"]
},
"title": { "type": "string" },
"items": {
"type": "array",
"minItems": 1,
"items": {
"type": "object",
"additionalProperties": false,
"properties": {
"image": {
"type": "string",
"format": "uri-reference",
"description": "Card image URL."
},
"favicon": {
"type": "string",
"format": "uri-reference",
"description": "Small brand/domain icon."
},
"eyebrow": {
"type": "string",
"description": "Superlative label, e.g. \"Cheapest\", \"Best battery\"."
},
"title": { "type": "string" },
"value": {
"type": "string",
"description": "Prominent value, e.g. \"$109 / night\"."
},
"subtitle": {
"type": "string",
"description": "Brand / domain / secondary line."
},
"body": {
"type": "string",
"description": "Description (wide-detail, source-tiles)."
},
"specs": {
"type": "array",
"description": "Small labeled stats (wide-detail).",
"items": {
"type": "object",
"required": ["label", "value"],
"additionalProperties": false,
"properties": {
"label": { "type": "string" },
"value": { "type": "string" }
}
}
},
"href": { "type": "string", "format": "uri-reference" }
}
}
}
},
"examples": [
{
"type": "cards",
"layout": "picks",
"items": [
{
"eyebrow": "Cheapest",
"value": "$109 / night",
"title": "Nijima Escape",
"subtitle": "airbnb.com",
},
{
"eyebrow": "Best reviews",
"value": "4.9 / 5",
"title": "Yado Marubun",
"subtitle": "expedia.com",
}
]
}
]
},
{
"$id": "list",
"title": "List block",
"description": "Sequences and sets. `checklist` = grouped actionable checkboxes; `side-title` = title left, groups right; `takeaways` = numbered claim + evidence; `big-number` = figure-led rundown. Use `groups` for checklist, `items` for the rest.",
"type": "object",
"required": ["type", "layout"],
"additionalProperties": false,
"anyOf": [{ "required": ["groups"] }, { "required": ["items"] }],
"properties": {
"type": { "const": "list" },
"layout": {
"enum": ["checklist", "side-title", "takeaways", "big-number"]
},
"title": { "type": "string" },
"showProgress": {
"type": "boolean",
"description": "For checklist: show done/total.",
"default": true
},
"groups": {
"type": "array",
"description": "Checklist groups (each carries a sequence).",
"items": {
"type": "object",
"required": ["heading", "items"],
"additionalProperties": false,
"properties": {
"heading": { "type": "string" },
"items": {
"type": "array",
"minItems": 1,
"items": {
"type": "object",
"required": ["text"],
"additionalProperties": false,
"properties": {
"text": { "type": "string", "minLength": 1 },
"done": { "type": "boolean", "default": false },
"due": { "type": "string", "format": "date" },
"priority": { "enum": ["low", "medium", "high"] },
"note": { "type": "string" },
"href": { "type": "string", "format": "uri-reference" }
}
}
}
}
}
},
"items": {
"type": "array",
"description": "Rows for takeaways (claim/body) or big-number (number/label/body).",
"items": {
"type": "object",
"additionalProperties": false,
"properties": {
"number": {
"type": "string",
"description": "Big figure (big-number) or index (takeaways, e.g. \"01\")."
},
"title": {
"type": "string",
"description": "Claim / label headline."
},
"body": { "type": "string", "description": "Supporting text." }
}
}
}
},
"examples": [
{
"type": "list",
"layout": "big-number",
"items": [
{
"number": "10 wks",
"title": "Start to finished kitchen",
"body": "Permit filing on Aug 4 through final inspection on Oct 12."
},
{
"number": "$34.5k",
"title": "Midpoint of the two quotes",
"body": "Bright Build came in at $31,200; Sterling at $37,800."
}
]
}
]
},
{
"$id": "timeline",
"title": "Timeline block",
"description": "Anything with dates. `phase-rail` = vertical rail with a current marker; `horizontal` = a few stops; `day-schedule` = hour-by-hour with a highlighted current slot; `side-title` = title left, phase rows right.",
"type": "object",
"required": ["type", "layout", "items"],
"additionalProperties": false,
"properties": {
"type": { "const": "timeline" },
"layout": {
"enum": ["phase-rail", "horizontal", "day-schedule", "side-title"]
},
"title": { "type": "string" },
"description": { "type": "string" },
"items": {
"type": "array",
"minItems": 1,
"items": {
"type": "object",
"required": ["title"],
"additionalProperties": false,
"properties": {
"label": {
"type": "string",
"description": "Date or time, e.g. \"Aug 4 – 15\" or \"9:00\"."
},
"sublabel": {
"type": "string",
"description": "Duration / period, e.g. \"2 weeks\", \"Morning\"."
},
"eyebrow": {
"type": "string",
"description": "Small uppercase marker, e.g. \"Now\", \"Fri evening\"."
},
"title": { "type": "string" },
"body": { "type": "string" },
"state": {
"enum": ["now", "done", "upcoming"],
"default": "upcoming",
"description": "Drives the filled/hollow dot and current-card styling."
}
}
}
}
},
"examples": [
{
"type": "timeline",
"layout": "phase-rail",
"title": "Project Timeline",
"items": [
{
"label": "Aug 4 – 15",
"sublabel": "2 weeks",
"eyebrow": "Now",
"title": "Permits & prep",
"body": "Drawings signed off, permit filed, temporary kitchen set up.",
"state": "now"
},
{
"label": "Oct 12",
"eyebrow": "Done",
"title": "Kitchen finished",
"body": "Ten weeks from the first permit to cooking dinner in it.",
"state": "upcoming"
}
]
}
]
},
{
"$id": "highlight",
"title": "Highlight block",
"description": "Soft 80px-radius boxes that pull one thing out of the page. `full-width` = a single dark hero verdict; `number-trio` = three big-number boxes; `verdict-pair` = two boxes (light vs dark).",
"type": "object",
"required": ["type", "layout"],
"additionalProperties": false,
"anyOf": [
{ "required": ["title"] },
{ "required": ["items"] },
{ "required": ["boxes"] }
],
"properties": {
"type": { "const": "highlight" },
"layout": { "enum": ["full-width", "number-trio", "verdict-pair"] },
"eyebrow": {
"type": "string",
"description": "Small uppercase kicker (full-width)."
},
"title": { "type": "string", "description": "Headline (full-width)." },
"body": {
"type": "string",
"description": "Supporting text (full-width)."
},
"items": {
"type": "array",
"description": "Three stat boxes (number-trio).",
"items": {
"type": "object",
"required": ["value", "label"],
"additionalProperties": false,
"properties": {
"value": {
"type": "string",
"description": "Big figure, e.g. \"-$210\", \"10%\"."
},
"label": { "type": "string" },
"body": { "type": "string" }
}
}
},
"boxes": {
"type": "array",
"description": "Two verdict boxes (verdict-pair).",
"minItems": 2,
"maxItems": 2,
"items": {
"type": "object",
"required": ["tone", "title"],
"additionalProperties": false,
"properties": {
"tone": { "enum": ["light", "dark"] },
"title": { "type": "string" },
"points": {
"type": "array",
"items": {
"type": "object",
"required": ["body"],
"additionalProperties": false,
"properties": {
"title": { "type": "string" },
"body": { "type": "string" }
}
}
}
}
}
}
},
"examples": [
{
"type": "highlight",
"layout": "number-trio",
"items": [
{
"value": "-$210",
"label": "Apple trade-in",
"body": "Quoted for a 2019 Air in good condition."
},
{
"value": "10%",
"label": "Student discount",
"body": "Both stores, with a verified .edu address."
},
{
"value": "$89",
"label": "Extra for 16GB",
"body": "Cheaper on the Dell than on the Air."
}
]
}
]
},
{
"$id": "field",
"title": "Field (shared)",
"description": "A column/attribute definition used by record-oriented table layouts. Carries display type, role, sort, schema.org mapping, and best-value goal.",
"type": "object",
"required": ["key", "type"],
"additionalProperties": false,
"properties": {
"key": {
"type": "string",
"description": "Property name read from each data object."
},
"label": { "type": "string" },
"type": {
"enum": [
"text",
"number",
"currency",
"rating",
"tags",
"badge",
"boolean",
"date",
"url",
"image",
"long"
]
},
"role": {
"enum": ["image", "title", "subtitle", "badge", "detail", "action"],
"default": "detail"
},
"sortable": { "type": "boolean" },
"prefix": { "type": "string" },
"suffix": { "type": "string" },
"max": {
"type": "number",
"description": "Denominator for `rating` (default 5)."
},
"currency": {
"type": "string",
"default": "USD",
"description": "ISO 4217 code for `currency`."
},
"property": {
"type": "string",
"description": "schema.org property; dotted paths nest (e.g. \"offers.price\")."
},
"goal": {
"enum": ["min", "max"],
"description": "Which direction is better; drives superlatives & best-value."
}
}
}
]