Skip to content
Cloaked Design SystemForms

Field

Own the label, helper text, and error for exactly one form control.

Implementation preview
01

See the decisions in action

Try a labelled input, enter a value, and explore the validation state. Field supplies the accessible relationships.

Live exampleReact · shared implementation
Try the controls. Your changes stay in this example.Open example
COMPLETE STORYBOOK REFERENCE

Every example. In one place.

Explore every named example, including states, compositions, and theme variants.

12 stories
SELECTED EXAMPLE

Playground

Open controls
Playground selectedOpen canvas
Example sourcepackages/design-system/src/components/forms/Field/Field.stories.tsxExport Playground

Implementation preview Local Storybook build 0.2.0-preview.1. Source specification status does not approve this runtime.

Stories + source JSON ↗
02

Choose the right responsibility

Input owns the control. Field owns the label and supporting message. Compose them instead of recreating the relationship.

USE WHEN
  • A control needs a visible label or explanatory message.
  • A validation error should also mark its control invalid.
  • A field is required or disabled as a unit.
AVOID
  • Placing two Field-aware controls inside one Field.
  • Duplicating error text below the Input.
  • Overriding control IDs or accessible labels without preserving the visible label association.
One Field. One compatible control.

Let Field associate its label and its one visible helper or error message with the child control. Set the error on Field once.

Explore Input
03

Small details carry the experience

Anatomy, feedback, and accessibility are part of the component contract.

1

LabelProvides the persistent visible and programmatic name for the child control.

2

Child controlExactly one compatible form control receiving label, message, required, disabled, and invalid wiring.

3

Helper messageSupporting copy shown only while there is no error.

4

Error messageCorrective copy that replaces helper text and marks the control invalid.

ACCESSIBILITY

Make the behavior available to everyone.

  • Field owns stable IDs for its label, description, and control.
  • An error replaces helper text and is referenced by aria-describedby.
  • Required markers are decorative; the child receives native required semantics.
IMPLEMENTATION CONTRACT

Keep the important relationships.

  • Compatible controls consume FieldContext at any nesting depth.
  • Explicit child props take precedence over context values.

This interactive implementation is for the web. Imported native specifications do not establish native implementation or parity.

Full component specification preview · 2.0.0

This versioned design-owned specification describes the implementation preview. It remains pending design and engineering sign-off.

{
  "$schema": "../../../specs/component-spec.schema.json",
  "identity": {
    "name": "Field",
    "status": "preview",
    "version": "2.0.0",
    "summary": "A form-control wrapper that owns visible labelling, optional label-side action, required state, helper copy, and validation — including the invalid state the child control renders."
  },
  "parts": [
    {
      "id": "root",
      "label": "Root",
      "description": "Stacks header, one compatible control, and one supporting message."
    },
    {
      "id": "header",
      "label": "Header",
      "description": "Aligns the visible label and optional label-side action."
    },
    {
      "id": "label",
      "label": "Label",
      "description": "Provides the persistent visible and programmatic name for the child control."
    },
    {
      "id": "required-mark",
      "label": "Required mark",
      "description": "Visually indicates required input without becoming part of the label text."
    },
    {
      "id": "action",
      "label": "Label-side action",
      "description": "Optional compact action related to the field, such as Add or Use current."
    },
    {
      "id": "control",
      "label": "Child control",
      "description": "Exactly one compatible form control receiving label, message, required, disabled, and invalid wiring."
    },
    {
      "id": "helper-message",
      "label": "Helper message",
      "description": "Supporting copy shown only while there is no error."
    },
    {
      "id": "error-message",
      "label": "Error message",
      "description": "Corrective copy that replaces helper text and marks the control invalid."
    }
  ],
  "allowedDesignChoices": {
    "variants": {
      "labelled": {
        "label": "Labelled",
        "description": "One field wrapper whose optional parts are configured independently."
      }
    },
    "sizes": {}
  },
  "variants": [
    {
      "id": "labelled",
      "label": "Labelled",
      "description": "Persistent label and message scaffolding around one compatible form control.",
      "platforms": [
        "ios",
        "android",
        "web"
      ]
    }
  ],
  "sizes": [],
  "measurements": [
    {
      "id": "stack-gap",
      "label": "Field stack gap",
      "kind": "exact",
      "token": "--cds-space-8",
      "value": 8,
      "unit": "px",
      "appliesTo": [
        "root",
        "header",
        "control",
        "helper-message",
        "error-message"
      ]
    },
    {
      "id": "header-gap",
      "label": "Label-to-action minimum gap",
      "kind": "exact",
      "token": "--cds-space-12",
      "value": 12,
      "unit": "px",
      "appliesTo": [
        "header",
        "label",
        "action"
      ]
    },
    {
      "id": "required-mark-gap",
      "label": "Label-to-required-mark gap",
      "kind": "exact",
      "token": "--cds-space-4",
      "value": 4,
      "unit": "px",
      "appliesTo": [
        "label",
        "required-mark"
      ]
    }
  ],
  "layout": {
    "alignment": "Label begins at the control edge while a label-side action remains trailing; messages align with the control.",
    "flow": "Optional header, exactly one child control, then either helper or error copy.",
    "notes": [
      "Use Field whenever a control needs a persistent visible label, supporting message, or validation; the label itself is optional.",
      "Do not place multiple controls under one Field instance."
    ]
  },
  "typographyAndColor": {
    "typography": [
      {
        "label": "Label and messages",
        "description": "Use body-small text for labels, helpers, and validation copy.",
        "token": "--cds-type-body-small-size"
      }
    ],
    "colors": [
      {
        "label": "Label",
        "description": "Use primary text emphasis for the persistent label.",
        "token": "--cds-text-primary"
      },
      {
        "label": "Helper",
        "description": "Use secondary emphasis for non-critical supporting copy.",
        "token": "--cds-text-secondary"
      },
      {
        "label": "Required and error",
        "description": "Use the readable semantic danger role for error indication in both themes.",
        "token": "--cds-text-danger"
      }
    ]
  },
  "states": [
    {
      "id": "default",
      "label": "Default",
      "description": "Shows the label and child control without supporting copy."
    },
    {
      "id": "helper",
      "label": "Helper",
      "description": "Associates non-critical supporting copy with the control."
    },
    {
      "id": "required",
      "label": "Required",
      "description": "Shows the visual mark and forwards required semantics."
    },
    {
      "id": "error",
      "label": "Error",
      "description": "Replaces helper copy, associates the error, and puts the child control into its invalid treatment."
    },
    {
      "id": "disabled",
      "label": "Disabled",
      "description": "Forwards disabled state while retaining label and supporting context."
    }
  ],
  "behavior": [
    {
      "label": "Child wiring",
      "description": "Publish id, disabled, required, labelled-by, described-by, and invalid to the child control, which fills in only the values it does not set itself."
    },
    {
      "label": "Invalid propagation",
      "description": "Publish invalid state to the child control so the control renders its own invalid treatment without the caller setting the error twice. A control that sets invalid itself keeps its own value. The wiring travels by context, so it still reaches a control nested inside a wrapper component."
    },
    {
      "label": "Message precedence",
      "description": "Show and associate error copy instead of helper copy whenever an error is present."
    },
    {
      "label": "Label-side action",
      "description": "Keep the optional action separate from the child control and give the action its own name and test identifier."
    }
  ],
  "accessibility": [
    {
      "label": "Persistent name",
      "description": "Bind the visible label to the child control through id and labelled-by relationships."
    },
    {
      "label": "Message relationship",
      "description": "Associate the one visible helper or error message through described-by."
    },
    {
      "label": "Required mark",
      "description": "Hide the decorative asterisk from assistive technology and forward required state to the control."
    }
  ],
  "contentAdaptation": [
    {
      "label": "Long labels",
      "description": "Allow the label to wrap while preserving space for a compact trailing action."
    },
    {
      "label": "Corrective errors",
      "description": "Write errors as specific correction guidance rather than repeating the label."
    }
  ],
  "motionHaptics": {
    "motion": [
      {
        "label": "Message replacement",
        "description": "Helper and error copy may replace one another without animating or moving the child control independently."
      }
    ],
    "haptics": [
      {
        "label": "No intrinsic feedback",
        "description": "Field owns no interaction; the child control and label-side action own their haptics."
      }
    ]
  },
  "platformDifferences": [
    {
      "platforms": [
        "web"
      ],
      "description": "Web associates the label and messages with DOM id and ARIA references; native implementations use platform accessibility labels, values, hints, and errors.",
      "rationale": "The visible hierarchy is shared while each platform uses its native form relationship APIs."
    }
  ]
}
04

Carry the decisions into code

The same component contract supports a person reading the page and an agent implementing it.

Agent handoff
Build a Field component using the Cloaked design system.
Read https://design.cloaked.team/data/components/field.json first.
Use the documented component API and semantic tokens.
Preserve keyboard access, clear labels, and validation behavior.
Treat this implementation as a review preview; report any missing requirements.
PUT IT TOGETHER

A complete protected-email flow.

Follow the same components through entry, validation, loading, and confirmation.

Explore the pattern
Implementation preview

This design-owned implementation is ready to try and review. It does not establish product approval. Imported specifications retain their original review status.

Inspect version 0.2.0-preview.1