Component format
Spec version: 1.0.0-draft (see Overview)
This document defines the normative component declaration object: identity ($id, name, displayName), component metadata (meta), platform implementations (implementations), API options (options), named content slots (slots), anatomy parts (anatomy), state model (states), and lifecycle metadata.
Component declarations close the structural gap between the token name-object's component, variant, anatomy, and state fields and the declared surface of each component. Before this chapter, a token referencing component: "button" with variant: "foo" was undetectable as invalid because no machine-readable component contract existed in the same spec. After this chapter, validators enforce cross-reference rules (see SPEC rules).
Scoped under RFC-A — Component Contract in Design Data Spec. See also rfc-coordination.md.
Document shape
A component declaration is a single JSON object in a .json file. One file per component. Files live under a components/ directory within a design-data package.
NORMATIVE: Each component declaration file MUST validate against the Layer 1 schema component.schema.json (canonical $id: https://opensource.adobe.com/spectrum-design-data/schemas/v0/component.schema.json). Layer 1 and Layer 2 validation are defined in the validation layers section of the overview.
Component object
Required fields
A component declaration MUST contain:
| Field | Type | Description |
|---|---|---|
$id |
URI string | Canonical identifier for this component declaration. |
name |
kebab-case string | Machine identifier; used as the value of the component field in token name objects. |
displayName |
string | Human-readable component name (e.g. "Button"). |
meta |
object | Category and documentation link — see Meta. |
Optional fields
| Field | Type | Description |
|---|---|---|
specVersion |
string | Declares which spec version this document targets. Currently "1.0.0-draft"; future stable releases will accept their own version string. |
description |
string | Plain-text description of the component's purpose. |
implementations |
array | Known platform implementations — see Implementations. |
options |
object | Component API options — see Options. |
slots |
array | Named content injection points — see Slots. |
anatomy |
array | Named anatomy parts — see Anatomy (stub). |
states |
array | Per-component state declarations — see States (stub). |
lifecycle |
object | Version lifecycle metadata — see Lifecycle. |
tokenBindings |
array | Tokens this component uses — see Token bindings (Phase 6.7). |
documentBlocks |
array | Typed prose blocks for this component — see Document blocks (Phase 9). |
accessibility |
object | Semantic accessibility vocabulary — see Accessibility (Phase 7). |
NORMATIVE: No properties beyond those listed above are permitted at the top level of a component declaration. Additional fields MUST cause a Layer 1 schema error.
$id
NORMATIVE: The $id MUST be a valid URI identifying this component declaration document. The recommended pattern is:
https://opensource.adobe.com/spectrum-design-data/schemas/v0/components/{name}.json
where {name} matches the component's name field.
name
NORMATIVE: name MUST match the pattern ^[a-z][a-z0-9-]*$ — lower-case kebab-case, non-empty.
NORMATIVE: name MUST be unique within a dataset. No two component declarations in the same design-data package may share a name value.
NORMATIVE: Token name-object component field values MUST match the name of a declared component in the dataset (rule SPEC-018). An undeclared component value is a validation error.
Meta
NORMATIVE: meta MUST contain:
| Field | Type | Values |
|---|---|---|
category |
string (enum) | actions, containers, data visualization, feedback, inputs, navigation, status, typography |
documentationUrl |
URI string | Link to the component's documentation page. |
"meta": {
"category": "actions",
"documentationUrl": "https://spectrum.adobe.com/page/button/"
}
Implementations
implementations declares the published platform implementations corresponding
to this design-system component. It is foundation-owned canonical data so
consumers, including Code Connect generators, can resolve an implementation
without platform-specific configuration.
Each entry MUST contain platform and componentName, plus exactly one
implementation reference: package for a published package or importPath
for an importable module/source path. notes is optional context for consumers.
Multiple entries MAY use the same platform when their packages distinguish
different implementations for that platform.
"implementations": [
{
"platform": "web",
"componentName": "Button",
"package": "@spectrum-web-components/button"
}
]
Platform manifests do not override implementations in this version. A future
extension may add platform-owned overrides after consumers need them; until
then, component declarations remain the canonical source of implementation
names and references.
Options
The options block declares the component's API surface — the configurable properties that affect its appearance or behavior. It mirrors the shape of @adobe/spectrum-component-api-schemas for backward compatibility.
NORMATIVE: options MUST be a JSON object. Each key is an option name; each value is an option descriptor.
Option descriptor
An option descriptor is a JSON object with the following fields:
| Field | Type | Required | Description |
|---|---|---|---|
type |
string or array | OPTIONAL | JSON Schema primitive type(s): "string", "boolean", "number", "integer". |
values |
array | OPTIONAL | Exhaustive list of permitted values, each an optionValue object. Use this instead of JSON Schema's enum keyword so per-value lifecycle metadata can be expressed without a separate sidecar map. |
default |
any | OPTIONAL | Default value when the option is not specified. |
description |
string | OPTIONAL | Plain-text description of what the option controls. |
$ref |
URI string | OPTIONAL | Reference to a shared type schema (e.g. workflow-icon.json). |
optionValue
Each entry in values is an object:
| Field | Type | Required | Description |
|---|---|---|---|
value |
any | REQUIRED | The permitted option value. |
description |
string | OPTIONAL | Plain-text description of what this value means. |
lifecycle |
object | OPTIONAL | Version lifecycle metadata. Set lifecycle.deprecated to signal migration via SPEC-037. |
NORMATIVE: Each key in options MUST be camelCase.
NORMATIVE: Boolean option names MUST begin with is or has (e.g. isDisabled, hasIcon).
NORMATIVE: When values is present, token name-object variant field values referencing this component MUST be drawn from the declared variant option values list (rule SPEC-019, Error). Token name-object keys matching any other declared option's values list SHOULD be drawn from that list (rule SPEC-040, Warning). Both rules are silent when no values array is declared for the option.
ADVISORY: When a value in values carries a lifecycle.deprecated string and a non-deprecated token references that value via its name object field, SPEC-037 fires an advisory warning prompting migration or token deprecation.
Example with a deprecated option value:
"variant": {
"type": "string",
"values": [
{ "value": "primary" },
{ "value": "secondary" },
{
"value": "cta",
"lifecycle": {
"deprecated": "1.0.0-draft",
"deprecatedComment": "Use primary instead."
}
}
]
}
"options": {
"variant": {
"type": "string",
"values": [
{ "value": "accent" },
{ "value": "negative" },
{ "value": "primary" },
{ "value": "secondary" }
],
"default": "accent",
"description": "Visual emphasis level."
},
"size": {
"type": "string",
"values": [
{ "value": "s" },
{ "value": "m" },
{ "value": "l" },
{ "value": "xl" }
],
"default": "m"
},
"isDisabled": {
"type": "boolean",
"default": false
},
"icon": {
"$ref": "https://opensource.adobe.com/spectrum-design-data/schemas/types/workflow-icon.json",
"description": "Icon placed at the start of the button. Required when hideLabel is true."
}
}
Slots
The slots block declares the component's named content injection points — the positions where consumers place child content. Slot declarations are derived from the cross-platform audit in audits/slots.audit.md.
NORMATIVE: slots MUST be a JSON array. Each element is a slot declaration.
Slot declaration
| Field | Type | Required | Description |
|---|---|---|---|
name |
string | REQUIRED | Slot identifier. SHOULD come from the canonical vocabulary (see below). |
description |
string | OPTIONAL | Plain-text description of what content goes in this slot. |
required |
boolean | OPTIONAL | Whether consumers MUST populate this slot. Default: false. |
Canonical slot vocabulary
The following slot names are defined by the cross-platform audit and SHOULD be used in preference to custom names:
| Name | Semantics |
|---|---|
default |
Primary content (text, children). The main content slot. |
icon |
Decorative icon at the leading edge of the component. |
label |
Human-readable identifier / placeholder text (distinct from default). |
help-text |
Non-error guidance text below a form field. |
negative-help-text |
Validation error message for a form field. |
action |
Secondary interactive button or call-to-action. |
heading |
Section or dialog heading. |
description |
Section or dialog body text (distinct from help-text). |
hero |
Large header media (e.g. dialog hero image). |
footer |
Below-content supplemental area (e.g. dialog footer). |
tooltip |
Floating annotation attached to the component. |
NORMATIVE: Custom slot names are permitted but SHOULD be documented in the slot's description field (rule SPEC-021 fires a warning for undocumented custom names).
RECOMMENDED: Components SHOULD declare a default slot when they accept primary child content.
"slots": [
{
"name": "default",
"description": "Text label of the button.",
"required": false
},
{
"name": "icon",
"description": "Icon placed at the start of the button. Required when isLabelHidden is true."
}
]
Anatomy (stub)
The anatomy block declares the component's named visual parts — the anatomy terms used in token name-object anatomy fields. Full normative definition is in spec/anatomy-format.md (Phase 6.2).
NORMATIVE: anatomy MUST be a JSON array. Each element is an anatomy part object.
NORMATIVE: Token name-object anatomy field values referencing this component MUST match the name of a declared anatomy part (rule SPEC-020).
Each anatomy part carries at minimum:
| Field | Type | Required | Description |
|---|---|---|---|
name |
string | REQUIRED | Anatomy part identifier (e.g. icon, label, handle). |
description |
string | OPTIONAL | Plain-text description of the part. |
required |
boolean | OPTIONAL | Whether this part is always present. Default: false. |
contains |
array of strings | OPTIONAL | Informative: other anatomy part names nested within this part. |
lifecycle |
object | OPTIONAL | Version lifecycle metadata for this part. When lifecycle.deprecated is set, SPEC-037 fires on referencing tokens. |
See spec/anatomy-format.md for constraints, cross-field validation, and the full anatomy part schema.
"anatomy": [
{ "name": "icon", "description": "Leading icon." },
{ "name": "label", "description": "Button text.", "required": true }
]
States (stub)
The states block declares the component's interactive and semantic states — the state terms used in token name-object state fields. Full normative definition is in spec/state-model.md (Phase 6.3).
NORMATIVE: states MUST be a JSON array. Each element is a state declaration object.
Each state carries at minimum:
| Field | Type | Required | Description |
|---|---|---|---|
name |
string | REQUIRED | State identifier (e.g. hover, focus, disabled). |
trigger |
string | OPTIONAL | "prop" for persistent prop-driven states (e.g. isDisabled) or "interaction" for runtime interaction states (hover, focus, pressed). |
precedence |
integer | OPTIONAL | Resolution precedence; higher integer wins when multiple states are active. |
layered |
boolean | OPTIONAL | true for states that compose with others (e.g. focus ring over hover). Default: false. |
lifecycle |
object | OPTIONAL | Version lifecycle metadata for this state. When lifecycle.deprecated is set, SPEC-037 fires on referencing tokens. |
See spec/state-model.md for the full state resolution algorithm, trigger semantics, and precedence rules.
"states": [
{ "name": "hover", "trigger": "interaction", "precedence": 50 },
{ "name": "focus", "trigger": "interaction", "precedence": 60, "layered": true },
{ "name": "disabled", "trigger": "prop", "precedence": 100 }
]
Lifecycle
The lifecycle block tracks a component declaration's version history. It mirrors the per-token lifecycle pattern from spec/token-format.md.
| Field | Type | Description |
|---|---|---|
introduced |
string | Spec version when this component declaration was added (e.g. "1.0.0-draft"). |
deprecated |
string | Spec version when this component was deprecated. Truthy = deprecated. |
deprecatedComment |
string | Human-readable explanation of the deprecation and migration path. |
replacedBy |
string or array | name value(s) of the replacement component(s). |
"lifecycle": {
"introduced": "1.0.0-draft"
}
Token bindings
The optional tokenBindings array declares which tokens a component uses, including foundation and structure tokens that do not carry the component name in their name-object. This is the component-declares-usage direction; the token-declares-scope direction is expressed via name-object component/anatomy/state fields and validated by SPEC-018–022.
"tokenBindings": [
{ "token": "component-height-100", "context": "Minimum height" },
{ "token": "corner-radius-full", "context": "Rounding" },
{ "token": "button-background-color-accent", "context": "Fill background" }
]
Each entry contains:
| Field | Required | Type | Description |
|---|---|---|---|
token |
yes | string | Token name. MUST resolve to a declared token in the dataset when the dataset is present (rule SPEC-027). May reference structure/foundation tokens. |
context |
no | string | Human-readable label for how this token is used (maps to the Figma Token Group label in the S2 Token Specs Figma file). |
NORMATIVE: When the dataset includes token declarations, each tokenBindings[].token value MUST match the name of a declared token (rule SPEC-027). A missing token reference is a validation error.
The context field is informative. It is used by describe_component (Phase 8 agent surface) to present token usage in grouped, human-readable form.
SPEC rules
The following rules are added to the Layer 2 rule catalog (rules/rules.yaml) by this chapter. New component cross-reference rules start at SPEC-018 to avoid collision with existing token rules (SPEC-001–SPEC-017).
| Rule ID | Name | Severity | Assert |
|---|---|---|---|
| SPEC-018 | component-name-exists |
error | Token component field value MUST match the name of a declared component in the dataset. |
| SPEC-019 | component-variant-valid |
error | Token variant field value MUST match a value in the declared variant option values list for the referenced component (when that list exists). |
| SPEC-020 | component-anatomy-valid |
error | Token anatomy field value MUST match the name of a declared anatomy part on the referenced component. |
| SPEC-021 | component-slot-vocabulary |
warning | Component slots entries with a name outside the canonical vocabulary SHOULD include a description. Custom slot names without descriptions are surfaced as warnings. |
| SPEC-022 | component-state-valid |
error | Token state field value MUST match the name of a declared state on the referenced component (when state declarations are present). |
| SPEC-027 | token-binding-token-exists |
error | Each tokenBindings[].token value MUST match the name of a declared token in the dataset (Phase 6.7). |
| SPEC-036 | component-deprecation-cascade |
warning | A non-deprecated token SHOULD NOT reference a deprecated component via name.component. Advisory warning prompts updating the component reference or marking the token deprecated. |
| SPEC-037 | sub-entity-deprecation-cascade |
warning | A non-deprecated token SHOULD NOT reference a deprecated anatomy part, state, or option value via name.*. Advisory warning prompts migration. Requires lifecycle on anatomy/state or lifecycle on the matching values entry on the option descriptor. |
| SPEC-038 | option-enum-obsolete |
warning | An option descriptor SHOULD NOT use the JSON Schema enum keyword. additionalProperties: true silently accepts enum at Layer 1; SPEC-038 flags it at Layer 2 so authors replace it with the values array. |
| SPEC-040 | component-option-field-valid |
warning | Token name-object keys that match a declared options.<key> with a values[] list SHOULD use a value drawn from that list. Generalises SPEC-019 to non-variant option fields (e.g. style, size, staticColor). Advisory; silent when no values declared. |
Full example
A complete button component declaration:
{
"$schema": "https://opensource.adobe.com/spectrum-design-data/schemas/v0/component.schema.json",
"$id": "https://opensource.adobe.com/spectrum-design-data/schemas/v0/components/button.json",
"specVersion": "1.0.0-draft",
"name": "button",
"displayName": "Button",
"description": "Buttons allow users to perform an action or to navigate to another page.",
"meta": {
"category": "actions",
"documentationUrl": "https://spectrum.adobe.com/page/button/"
},
"options": {
"variant": {
"type": "string",
"values": [
{ "value": "accent" },
{ "value": "negative" },
{ "value": "primary" },
{ "value": "secondary" }
],
"default": "accent",
"description": "Visual emphasis level."
},
"style": {
"type": "string",
"values": [{ "value": "fill" }, { "value": "outline" }],
"default": "fill"
},
"size": {
"type": "string",
"values": [
{ "value": "s" },
{ "value": "m" },
{ "value": "l" },
{ "value": "xl" }
],
"default": "m"
},
"isDisabled": { "type": "boolean", "default": false },
"isPending": { "type": "boolean", "default": false },
"isLabelHidden": { "type": "boolean", "default": false },
"icon": {
"$ref": "https://opensource.adobe.com/spectrum-design-data/schemas/types/workflow-icon.json",
"description": "Icon placed at the start of the button. Required when isLabelHidden is true."
},
"staticColor": {
"type": "string",
"values": [{ "value": "white" }, { "value": "black" }],
"description": "Static color for use on colored backgrounds. Must not be set for the default variant."
}
},
"slots": [
{
"name": "default",
"description": "Text label of the button.",
"required": false
},
{
"name": "icon",
"description": "Icon placed at the start of the button."
}
],
"anatomy": [
{ "name": "icon", "description": "Leading icon." },
{ "name": "label", "description": "Button text.", "required": true }
],
"states": [
{ "name": "hover", "trigger": "interaction", "precedence": 50 },
{ "name": "focus", "trigger": "interaction", "precedence": 60, "layered": true },
{ "name": "disabled", "trigger": "prop", "precedence": 100 }
],
"lifecycle": {
"introduced": "1.0.0-draft"
}
}
Accessibility
Phase 7. Component declarations MAY carry an accessibility object at the top level. State declarations MAY carry announce, communicates, and blocksInteraction fields. See spec/accessibility.md for the full vocabulary, SPEC rules, and examples.
{
"name": "button",
"displayName": "Button",
"meta": { "category": "actions", "documentationUrl": "https://spectrum.adobe.com/page/button/" },
"accessibility": {
"role": "button",
"intents": ["trigger"],
"focusable": true,
"keyboardIntents": ["activate"],
"wcag": [
{ "criterion": "4.1.2", "level": "A", "title": "Name, Role, Value" }
]
},
"states": [
{
"name": "disabled",
"trigger": "prop",
"precedence": 100,
"announce": "Button disabled",
"communicates": "disabled",
"blocksInteraction": true
}
]
}
Document blocks
Phase 9. Component declarations MAY carry a documentBlocks array at the top level, and individual anatomy parts MAY carry their own documentBlocks arrays. See spec/document-blocks.md for the full block schema, type vocabulary, and SPEC rules.
{
"name": "button",
"displayName": "Button",
"meta": { "category": "actions", "documentationUrl": "https://spectrum.adobe.com/page/button/" },
"documentBlocks": [
{
"type": "purpose",
"content": "Buttons trigger a discrete action or event.",
"agents": "Use Button when the user must trigger an action. For navigation, use Link."
}
],
"anatomy": [
{
"name": "label",
"required": true,
"documentBlocks": [
{
"type": "guideline",
"content": "Button labels should be action verbs (Save, Delete, Submit)."
}
]
}
]
}