Skip to main content

Field

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

In Dense data

See it live​

Start Storybook to see it live: npm run storybook

When to use it​

In Dense data: Lays out label, control and error the same way everywhere.

  • 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 Dense data decided and why. Each sample is the live story with that variant set.

verticalorientationUsed in Dense data
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 Dense data

Forms in dialogs and sheets: the label above.

horizontalorientationUsed in Dense data
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 Dense data

Settings and filter panels: switches and short controls with the label beside.

responsiveorientationNot used in Dense data
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 Dense data

A desk with a mouse and keyboard: there is no narrow screen to adapt to.

How Dense data uses it​

Field label or column header
Use type.label
Not type.heading
Headers repeat on every column; a heavy style would compete with the data.
An error message
Use color.status.danger with an icon
Not color.status.warning
Red always means fix this, and the icon says it without color.

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 is the main task?tasks.q1
1The answer
Scan and compare

People scan rows and compare values.

2So Field
  • ✓uses vertical: Forms in dialogs and sheets: the label above.
It also shapes Item: muted
3If it changed
2
Field decisions would reopen

and 20 answers that follow from it: People keep their place, Acting on the wrong record, Core and data, and 17 more.

How much is on one screen?content.q2
1The answer
A lot

Experts want many records on one screen.

2So Field
  • ✓uses horizontal: Settings and filter panels: switches and short controls with the label beside.
It also shapes Button: default Button: compact Button: large Input group: block-start Input group: block-end Sidebar: lg Toggle: default Toggle: sm Toggle: lg
3If it changed
1
Field decision would reopen

and 14 answers that follow from it: Quiet, Only the steps the screens need, Small, and 11 more.

How many densities exist?spacing.count
1The answer
Two

A second, denser size serves tables and toolbars.

2So Field
  • ✓uses horizontal: Settings and filter panels: switches and short controls with the label beside.
It also shapes Sidebar: sm Item: default Item: sm
3If it changed
1
Field decision would reopen

No other answer follows from it.

Where do people use it?scenarios.q1
1The answer
At a desk

Experts work at a desk with a mouse and keyboard.

2So Field
  • –does not use responsive: A desk with a mouse and keyboard: there is no narrow screen to adapt to.
3If it changed
1
Field decision would reopen

and 2 answers that follow from it: Compact, for a pointer, A use scenario needs it.

Words​

  • Lead with the object, then the state: "Alert 2041 contained."
  • Use numbers, not words for numbers.
  • One verb per button. No "please", no exclamation marks.
  • Use: Investigate, Filter, Assign, Escalated, Resolved. Avoid: Oops, Awesome, Please, Simply.

The labels components use, from the voice tokens:

  • content.action.commit: Save
  • content.action.cancel: Cancel
  • content.action.destroy: Delete
  • content.action.retry: Retry
  • content.action.empty-action: Change filters

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

Dense data 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.24:1.5rem
Gap 2component.field.set.gap-2component-spacing-map.x3var(--field-set-gap-2)space.12:0.75rem
Legend
Weightcomponent.field.legend.font-weighttype.label.font-weightvar(--field-legend-font-weight)font.weight.500:500
Text sizecomponent.field.legend.font-sizetype.body.font-sizevar(--field-legend-font-size)font.size.14:0.875rem
Group
Gapcomponent.field.group.gapcomponent-spacing-map.x8var(--field-group-gap)space.32:2rem
Gap 2component.field.group.gap-2component-spacing-map.x3var(--field-group-gap-2)space.12:0.75rem
Gap 3component.field.group.gap-3space.gap.groupvar(--field-group-gap-3)space.16:1rem
Field
Gapcomponent.field.gapcomponent-spacing-map.x3var(--field-gap)space.12:0.75rem
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)Lightviolet.light.600:#4B3FD9Darkviolet.dark.600:#A9A3F6
Background checked
Changes with theme
when on
component.field.background-checkedcolor.action.primaryvar(--field-background-checked)Lightviolet.light.600:#4B3FD9Darkviolet.dark.600:#A9A3F6
Fill
Changes with theme
component.field.backgroundcolor.surface.canvasvar(--field-background)Lightslate.light.50:#F7F8FADarkslate.dark.0:#0D1117
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.4:0.25rem
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.8:0.5rem
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.2:0.125rem
Paddingcomponent.field.label.paddingcomponent-spacing-map.x4var(--field-label-padding)space.16:1rem
Text sizecomponent.field.label.font-sizetype.body.font-sizevar(--field-label-font-size)font.size.14:0.875rem
Weightcomponent.field.label.font-weighttype.label.font-weightvar(--field-label-font-weight)font.weight.500:500
Color
Changes with theme
component.field.labelcolor.text.mutedvar(--field-label)Lightslate.light.600:#535D6DDarkslate.dark.400:#969FAD
Description
Text sizecomponent.field.description.font-sizetype.body.font-sizevar(--field-description-font-size)font.size.14:0.875rem
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)Lightslate.light.600:#535D6DDarkslate.dark.400:#969FAD
Label 2
Changes with theme
component.field.description.label-2color.action.primaryvar(--field-description-label-2)Lightviolet.light.600:#4B3FD9Darkviolet.dark.600:#A9A3F6
Separator
Text sizecomponent.field.separator.font-sizetype.body.font-sizevar(--field-separator-font-size)font.size.14:0.875rem
Error
Text sizecomponent.field.error.font-sizetype.body.font-sizevar(--field-error-font-size)font.size.14:0.875rem
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
Lightslate.light.200 · #DDE2EADarkslate.dark.100 · #262D38