Skip to main content

Form

Form state and validation wired to the fields.

In Dense data

See it live​

Start Storybook to see it live: npm run storybook

When to use it​

In Dense data: Keeps validation and errors the same on every record edit.

  • Use it when: Any form that checks answers and shows errors next to the fields.
  • Not when: A single control that saves at once (a switch).

Instead:

  • Field: How one control is laid out.

How Dense data uses it​

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.
The words of an error
Use Name the record, then the fix. Flat and specific.
Not "Oops" or a vague apology
Experts act on the message; the record and the fix are all they need. Example: “Alert ALR-2042 not saved. Threshold must be between 0 and 100.”

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:

  • Errors are announced, linked to their fields, and the first one gets focus on submit. undefined

Use it in code​

npx open-ds add form

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

Tokens it reads​

Form reads 6 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 Form's tokens to change Form 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
Item
Gapcomponent.form.item.gapspace.gap.defaultvar(--form-item-gap)space.8:0.5rem
Text
Text
Changes with theme
component.form.label.labelcolor.status.dangervar(--form-label-label)Lightred.light.600:#C42B2BDarkred.dark.600:#F28B8B
Description
Text sizecomponent.form.description.font-sizetype.body.font-sizevar(--form-description-font-size)font.size.14:0.875rem
Text
Changes with theme
component.form.description.labelcolor.text.mutedvar(--form-description-label)Lightslate.light.600:#535D6DDarkslate.dark.400:#969FAD
Message
Text sizecomponent.form.message.font-sizetype.body.font-sizevar(--form-message-font-size)font.size.14:0.875rem
Text
Changes with theme
component.form.message.labelcolor.status.dangervar(--form-message-label)Lightred.light.600:#C42B2BDarkred.dark.600:#F28B8B