Skip to main content

Field

A label, control, hint and error laid out together, the same way every time.

In Content first

See it live​

Start Storybook to see it live: npm run storybook

When to use it​

In Content first: Lays out the newsletter and search forms.

  • Use it when: Every form control that needs a label, a hint or an error.
  • Not when: A control that is not part of a form, such as a search box in a toolbar.

Instead:

  • Label: The label on its own.

Variants​

What each variant is for in any design system, then what Content first decided and why. Each sample is the live story with that variant set.

verticalorientationUsed in Content first
Start Storybook to see it live

What it is for

The label above the control.

✓Most forms: easy to scan from top to bottom.
✕Short settings where the label sits better beside.

In Content first

Newsletter and search forms: the label above.

horizontalorientationNot used in Content first
Start Storybook to see it live

What it is for

The label beside the control.

✓Settings and short controls such as switches.
✕Narrow screens, or long labels.

In Content first

Forms are rare and short; stacking keeps the reading column.

responsiveorientationNot used in Content first
Start Storybook to see it live

What it is for

The label above on narrow screens and beside on wide ones.

✓Forms people use on phones and laptops alike.
✕When one layout is simpler for everyone.

In Content first

One stacked layout reads the same on phones and laptops.

How Content first uses it​

Field label or column header
Use type.label
Not type.caption
Caption is too faint for a label people must read.
An error message
Use color.status.danger and a plain sentence
Not Color alone
The sentence says what to fix; color only draws the eye.

Why it works this way​

Field looks the way it does because of 4 answers about this product. Each card is one answer, in three steps: the answer, what it decided for Field, and what would move if it changed.

What accessibility level do we commit to?people.q2
1The answer
AA

AA is the commitment for a public site.

2So Field
  • ✓uses vertical: Newsletter and search forms: the label above.
It also shapes Button: focus Button: disabled
3If it changed
1
Field decision would reopen

and 3 answers that follow from it: A ratio, line heights in proportion, Two: color and word, AA.

How often do people repeat actions?tasks.q2
1The answer
Rarely

Actions are rare: subscribe, share, save.

2So Field
  • –does not use horizontal: Forms are rare and short; stacking keeps the reading column.
It also shapes Button: primary Button: large Input group: block-start Input group: block-end
3If it changed
1
Field decision would reopen

and 2 answers that follow from it: Three, Only what today's screens use.

What must the interface protect?human.q1
1The answer
Attention on the content

Attention belongs to the text.

2So Field
  • –does not use horizontal: Forms are rare and short; stacking keeps the reading column.
It also shapes Button: large Empty: default Item: muted
3If it changed
1
Field decision would reopen

and 8 answers that follow from it: Surface, text, action and status, Only what floats, One, and 5 more.

Where do people use it?scenarios.q1
1The answer
Anywhere, on any device

Readers arrive on phones and laptops alike.

2So Field
  • –does not use responsive: One stacked layout reads the same on phones and laptops.
3If it changed
1
Field decision would reopen

and 4 answers that follow from it: Light and dark, Touch size, Two, and 1 more.

Words​

  • Write to one person: "you", not "users".
  • Short sentences with room to breathe.
  • Explain why before asking for anything.
  • Use: Read, Save for later, You, Next issue. Avoid: Click here, Submit, Users, Content.

The labels components use, from the voice tokens:

  • content.action.commit: Save
  • content.action.cancel: Not now
  • content.action.destroy: Remove
  • content.action.retry: Try again
  • content.action.empty-action: Browse guides

See Voice and tone for the whole voice.

Accessibility and keyboard​

Test before you ship:

  • The label, hint and error are linked to the control, so they are read with it. undefined

Use it in code​

npx open-ds add field

The component reads only component keys and semantic tokens, so it follows the brand and mode on <html>.

Tokens it reads​

Field reads 30 tokens of its own, each an alias of a semantic token. Each row is one part: its own token, the semantic it aliases, and the value it ends at. Change a semantic and every component that reads it follows; override one of Field's tokens to change Field alone.

Changes with theme

Content first decides what changes when you switch theme. Here a switch changes colors only, so the marked rows differ between light and dark; everything else holds steady.

PartIts token and the semantic it aliasesValue
Set
Gapcomponent.field.set.gapspace.gap.sectionvar(--field-set-gap)space.64:4rem
Gap 2component.field.set.gap-2component-spacing-map.x3var(--field-set-gap-2)space.20:1.25rem
Legend
Weightcomponent.field.legend.font-weighttype.label.font-weightvar(--field-legend-font-weight)font.weight.600:600
Text sizecomponent.field.legend.font-sizetype.body.font-sizevar(--field-legend-font-size)font.size.18:1.125rem
Group
Gapcomponent.field.group.gapcomponent-spacing-map.x8var(--field-group-gap)space.48:3rem
Gap 2component.field.group.gap-2component-spacing-map.x3var(--field-group-gap-2)space.20:1.25rem
Gap 3component.field.group.gap-3space.gap.groupvar(--field-group-gap-3)space.32:2rem
Field
Gapcomponent.field.gapcomponent-spacing-map.x3var(--field-gap)space.20:1.25rem
Label invalid
Changes with theme
when invalid
component.field.label-invalidcolor.status.dangervar(--field-label-invalid)Lightred.light.600:#C42B2BDarkred.dark.600:#F28B8B
Border checked
Changes with theme
when on
component.field.border-checkedcolor.action.primaryvar(--field-border-checked)Lightnavy.light.600:#1E3A5FDarknavy.dark.600:#8FA6C4
Background checked
Changes with theme
when on
component.field.background-checkedcolor.action.primaryvar(--field-background-checked)Lightnavy.light.600:#1E3A5FDarknavy.dark.600:#8FA6C4
Fill
Changes with theme
component.field.backgroundcolor.surface.canvasvar(--field-background)Lightstone.light.50:#FFFDF8Darkstone.dark.0:#14110D
Padding, left and rightcomponent.field.padding-xcomponent-spacing-map.x2var(--field-padding-x)space.8:0.5rem
Gap 2component.field.gap-2space.gap.tightvar(--field-gap-2)space.8:0.5rem
Content
Gapcomponent.field.content.gapcomponent-spacing-map.x2var(--field-content-gap)space.8:0.5rem
Text
Gapcomponent.field.label.gapspace.gap.defaultvar(--field-label-gap)space.16:1rem
Disabled opacity disabled
when disabled
component.field.label.disabled-opacity-disabledopacity.disabledvar(--field-label-disabled-opacity-disabled)opacity.40:0.4
Cornercomponent.field.label.radiusradius.controlvar(--field-label-radius)radius.8:0.5rem
Paddingcomponent.field.label.paddingcomponent-spacing-map.x4var(--field-label-padding)space.24:1.5rem
Text sizecomponent.field.label.font-sizetype.body.font-sizevar(--field-label-font-size)font.size.18:1.125rem
Weightcomponent.field.label.font-weighttype.label.font-weightvar(--field-label-font-weight)font.weight.600:600
Color
Changes with theme
component.field.labelcolor.text.mutedvar(--field-label)Lightstone.light.600:#61594DDarkstone.dark.400:#A39A8B
Description
Text sizecomponent.field.description.font-sizetype.body.font-sizevar(--field-description-font-size)font.size.18:1.125rem
Weightcomponent.field.description.font-weighttype.body.font-weightvar(--field-description-font-weight)font.weight.400:400
Text
Changes with theme
component.field.description.labelcolor.text.mutedvar(--field-description-label)Lightstone.light.600:#61594DDarkstone.dark.400:#A39A8B
Label 2
Changes with theme
component.field.description.label-2color.action.primaryvar(--field-description-label-2)Lightnavy.light.600:#1E3A5FDarknavy.dark.600:#8FA6C4
Separator
Text sizecomponent.field.separator.font-sizetype.body.font-sizevar(--field-separator-font-size)font.size.18:1.125rem
Error
Text sizecomponent.field.error.font-sizetype.body.font-sizevar(--field-error-font-size)font.size.18:1.125rem
Weightcomponent.field.error.font-weighttype.body.font-weightvar(--field-error-font-weight)font.weight.400:400
Text
Changes with theme
component.field.error.labelcolor.status.dangervar(--field-error-label)Lightred.light.600:#C42B2BDarkred.dark.600:#F28B8B
From the system
Edge
Changes with theme
color.border.default
straight from the system, through --border
Lightstone.light.200 · #E4DDD0Darkstone.dark.100 · #2E2A24