Menu


Field


The frame around one form control: its label with an optional required mark, and help text or an error message under the control.

Customize the preview


Choices
Show
Flags
View

We send the receipt here.

Options


Field options
ChoiceValuesDefaultWhat it does
layoutsmbk-field--layout-<value>stackedside-by-sidestacked
Stacked puts the label above the control. Side by side puts it on the left of a small control, for settings; in a narrow space the field stacks.
errorsmbk-field--errorOn or offOff
The value is invalid. The label and the message under the control turn the danger color, the message leads with an icon, and the control draws its danger border and icon.
disabledsmbk-field--disabledOn or offOff
The control is disabled. The label, its mark and the help text take the disabled color.
readonlysmbk-field--readonlyOn or offOff
The control can be read and copied, not changed. It keeps its place in the tab order.

Partssmbk-field__labelsmbk-field__descriptionsmbk-field__warning

Examples


Usage

A label over the control, with help text under it.

We send the receipt here.

Required

The red mark says the field must be filled.

Error

The message takes the help text’s place, leads with an icon and says how to put it right. A screen reader reads it as it appears.

Disabled

The label, the help text and the control dim together.

Set when the workspace was made.

Read only

The control can be read and copied, not changed; the label and help text stay as they are.

Copy it into a support request.

With a select

The slot holds a select.

Sets what this person can change.

Guidelines


Purpose

The frame that turns a bare control into a form question: a label above it that stays while the reader types, an optional mark saying it must be filled, and a line under it with help or, when something is wrong, the error message. It holds one control, as Figma's slot does: an input, a select or a text area. It does not draw the control and never decides when a value is wrong; the form does.

When to use

  • Every form control that the reader fills in: a name, an email, a role, a message.
  • A single control on its own, such as a field inside a popover.

When not to use

  • A group of checkboxes or radios under one question. Use the field group, a fieldset with its legend.
  • A search box at the top of a list, named by what is around it. Use the search field with an aria-label.

Usage rules

Do

  • Name the value in the label ("Email address"), not the instruction ("Enter your email").
  • Write an error message that says how to put it right.
  • Keep the help text short: one line in most widths.

Don't

  • Use the placeholder as the only label.
  • Show an error before the reader has had a chance to answer.
  • Put two controls in one field.
Do

Say what is wrong and how to fix it, so the reader can put it right without guessing.

Don't

A bare “Invalid” tells the reader something failed but not what to change.

Anatomy

  • The block, a column spaced by the small stack step. Side by side, two columns: the label on the left, as tall as a small control so its words sit on the control's middle; the control on the right at a fixed width, with its line under it.
  • The label part, the label component in its subtle tone, with its required mark when the field is required.
  • The control, the field's own child, unwrapped: an input, a select, a text area or a search field. Its width and states are its own.
  • The description part, a line under the control: a field message of the help type, carrying the field's class beside its own. In error it is a field message of the error type, a circled-cross icon and the error message, in the help text's place, with the same class.
  • The warning part, optional: a field message of the warning type under the help text or the error, for something to notice that is not an error, such as Caps Lock being on in a password field.

Behavior

The field passes its state to the control: it gives the control its id unless it has one, links the line under it to it, marks it required, makes it disabled or read-only, and, in error, turns on the control's danger border and icon. The system's controls read all of this from the field around them, so a control inside a site's own component, such as a wrapper that adds a site's behaviour, is still named, described and marked by the field, though the wrapper passes nothing on. In error, the label and the message take the danger text color, as Figma binds them, and the message leads with its icon. Given an error message, the line shows the message in place of the help text; given only that the field is in error, it shows the help text as the message. Nothing in the field moves. Disabled, the label, its mark and the help text dim with the control. Read-only, only the control changes: it can be read and copied, not changed.

A warning is a line of its own under the help text or the error, with the warning icon; it does not mark the field invalid and does not stop the form. While the page passes null for it, the field keeps an empty place for it that takes no room, and the warning fills that place when it comes.

The id the field makes can change when the page changes, so give the control its own id when the page needs one that stays the same, such as for tests or a page rendered ahead of time.

The field fills the width of its container; the form decides how wide it is.

Two layouts. Stacked puts the label above the control. Side by side puts the label on the left of the control, for a column of settings: give the control its small size, since the label lines up with a small control's middle. The page keeps its order, label, control, line, so a screen reader and the Tab key meet them as before; only the layout moves. In a narrow space a side-by-side field stacks.

The select has no help line of its own. Put a select inside a field to give it help text.

Accessibility


What it does for you

  • The label is a real label element tied to the control, so it names the control and a press on it reaches the control. It also names the control through aria-labelledby, which is what names a select's open list; a control given its own aria-label or aria-labelledby keeps it.
  • The line under the control describes it through aria-describedby, so help and error messages are read with the control. The control's own aria-describedby is kept as well.
  • An error marks the control invalid (aria-invalid) as well as turning it red. The message is an alert, so a screen reader reads it out as it appears, and the icons in the control and before the message make the error a shape as well as a color.
  • A warning is a status: a screen reader reads it when it appears, once it has finished what it is saying, and reads it again with the control while it shows. It is announced only when its place was already on the page.
  • Read-only keeps the control in the tab order, so its value can still be reached and read; disabled takes it out.
  • The required mark is decorative; the control itself is marked required (the native attribute, or aria-required on the select).

What you must do

  • Always give a message with an error. Given error with no message, the field shows its help text as the message, which may not say what is wrong. The message should say what to change.
  • Pass null for the warning while there is none, rather than leaving the prop out, so its place is on the page before the words arrive.
  • Put any limit the reader must meet in the help text, so it is known before the first try. The help text comes before any error and is replaced by the message only when one is given.

How to test

  • With a screen reader, focus the control: it is read by its label, then its help or error, and as required where it is.
  • Press the label with a pointer: focus moves to the control.
  • Cause an error: the message is read as it appears and the control is read as invalid.
  • With the colors removed, the error icons and the message still say something is wrong.
  • Tab to a read-only control: it takes focus. A disabled one does not.
  • With text at 200% and the page 320 pixels wide, the label, control and line stay whole.
  • In a forced-color mode, the control, its icons and the message are still visible.

Source


The files the field is made of. Its folder on GitHub (opens in a new tab) holds them with its wrapper and its document.

Stylesheet
field.css
/* smbk-field — Field. Figma "Field" 4800:63897 (State: Default, Error, Disabled, Read-only × Layout: Stacked, Side by side).
 * A column: the label component in its subtle tone with the optional required
 * mark, then the control Figma's slot holds (an input, a select or a text
 * area, each drawing its own well), then the field message: a line of help
 * text, or the error message in its place. The control is not wrapped: it is
 * the field's own child, so its width and states are its own. In error, the
 * label and the message take the danger text color, as Figma binds them, the
 * message leads with an icon, and the control draws its danger border and
 * icon. Disabled, the label, its mark and the help text take the disabled
 * text color. Side by side, the label sits on the left of the control. */

.smbk-field {
  box-sizing: border-box;
  display: flex;
  flex-direction: column;
  gap: var(--smbk-space-stack-sm);
  width: 100%;
  min-width: 0;
}

/* The label hugs its words, so only they take a press, as Figma's label hugs. */
.smbk-field__label {
  align-self: flex-start;
}

/* The line under the control is the field message, whose own stylesheet draws it. The field's description class
   only turns its words to the danger color in an error and to the disabled color when disabled. */
.smbk-field--error .smbk-field__label,
.smbk-field--error .smbk-field__description {
  color: var(--smbk-color-feedback-danger-text-on-subtle);
}

.smbk-field--disabled .smbk-field__label,
.smbk-field--disabled .smbk-label__required,
.smbk-field--disabled .smbk-field__description {
  color: var(--smbk-color-text-disabled);
}

/* The warning's place, kept on the page while there is no warning so a screen reader hears one arrive, takes
   no room and no gap until it has words. */
.smbk-field__warning:empty {
  position: absolute;
}

/* ---- side by side: the label in a column on the left, as tall as a small control so its words sit
   on the control's middle; the control on the right at Figma's width, its message under it. The order
   in the page stays label, control, message: only the layout moves. ---- */

.smbk-field--layout-side-by-side {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, var(--smbk-size-field-control-width));
  align-items: start;
  column-gap: var(--smbk-space-stack-md);
  row-gap: var(--smbk-space-stack-xs);
}

.smbk-field--layout-side-by-side > * {
  grid-column: 2;
}

.smbk-field--layout-side-by-side > .smbk-field__label {
  grid-column: 1;
  grid-row: 1 / span 2;
  justify-self: start;
  min-height: var(--smbk-size-control-sm);
}

/* A narrow space has no room for two columns: the field stacks. */
@container style(--smbk-layout: narrow) {
  .smbk-field--layout-side-by-side {
    display: flex;
    gap: var(--smbk-space-stack-sm);
  }

  .smbk-field--layout-side-by-side > .smbk-field__label {
    min-height: 0;
  }
}
Tokens it reads
Field tokens
Token and CSSValuePreviewFoundation
space.stack.sm--smbk-space-stack-smcomfortable: 8pxcompact: 6pxchanges with densitySpacing
color.feedback.danger.text-on-subtle--smbk-color-feedback-danger-text-on-subtlelight: #a51d17dark: #febdb2changes with themeColor
color.text.disabled--smbk-color-text-disabledlight: #7c8692dark: #606a75changes with themeColor
size.field.control.width--smbk-size-field-control-width200pxSize
space.stack.md--smbk-space-stack-mdcomfortable: 12pxcompact: 8pxchanges with densitySpacing
space.stack.xs--smbk-space-stack-xs4pxSpacing
size.control.sm--smbk-size-control-smcomfortable: 32pxcompact: 28pxchanges with densitySize
Manifest
field.manifest.json
{
  "name": "field",
  "block": "smbk-field",
  "summary": "The frame around one form control: its label with an optional required mark, and help text or an error message under the control.",
  "adapt": "css",
  "axes": {
    "layout": {
      "values": [
        "stacked",
        "side-by-side"
      ],
      "default": "stacked",
      "description": "Stacked puts the label above the control. Side by side puts it on the left of a small control, for settings; in a narrow space the field stacks."
    }
  },
  "flags": {
    "error": {
      "description": "The value is invalid. The label and the message under the control turn the danger color, the message leads with an icon, and the control draws its danger border and icon."
    },
    "disabled": {
      "description": "The control is disabled. The label, its mark and the help text take the disabled color."
    },
    "readonly": {
      "description": "The control can be read and copied, not changed. It keeps its place in the tab order."
    }
  },
  "parts": [
    "label",
    "description",
    "warning"
  ],
  "figmaNodeId": "4800:63897"
}