Design System

Inputs & form controls

One reusable input system: text fields, native input types, selects, multi-select, textareas, icon affordances, validation messaging and three sizes — every example renders the production component.

What is this?

The V2 data-entry layer. Every control shares one chrome (border, radius, focus ring, placeholder colour), one label and messaging structure, and one set of three sizes, so a form built from any mix of them reads as a single system.

When to use it

  • Any field where a person types, picks or adjusts a value.
  • Forms that need consistent validation messaging across control types.
  • Dense enterprise tables and toolbars (small size) as well as focused wizards (large).

How to use it

  • Always pass `label`; use `aria-label` only inside composed groups.
  • Express state with `errorText`, `warningText` or `successText` — never colour alone.
  • Reach for the typed input (EmailInput, DateInput…) instead of a bare `type` attribute.
  • Input fields use a maximum of one supporting icon, positioned on the right. Left-side supporting icons are not used in the V2 input system.

What to avoid

  • Left-side icons, two icons on one field, or an icon that repeats a native control.
  • One-off className overrides for height, padding or border colour.
  • Placeholders used as labels.
  • Helper text carrying required information that should be a description or error.

Standardized values

Every control resolves these from V1 tokens. No new token candidates were required for the input system.

V2 input specification — resolved token per property and size.
PropertySmallMediumLargeToken
Height32px40px48px--ds-space-8 / 10 / 12
Horizontal padding12px12px12px--ds-space-3
Input typographybody-smbody-mdbody-md--ds-text-body-*
Label typographylabel-mdlabel-mdlabel-md--ds-text-label-md
Label spacing6px6px6pxField gap (--ds-space-1.5)
Icon size16px16px16px--size-icon-sm
Icon inset (right only)16px inset16px inset16px insetpr-10
Icons per fieldmax 1, rightmax 1, rightmax 1, rightV2 input icon rule
Border1px1px1px--ds-border-width-thin
Border radius8px8px8px--ds-radius-md
Focus ring2px offset ring2px offset ring2px offset ringds-focus-ring
Placeholdertertiary texttertiary texttertiary text--color-text-tertiary
Disabledmuted surface + disabled text——--color-background-muted
Error / warning / successborder + icon + message——--color-error / warning / success

Text inputs

The single-line field every other text control is built from: label, optional description, helper text and validation messaging in a fixed vertical rhythm.

import { Input } from "@/design-system";

When to use

  • Short free-text values
  • Identifiers, names, references

When not to use

  • Multi-line content — use Textarea
  • Choosing from a known set — use Select

States

Default, placeholder, filled, readonly, disabled, required, optional, error, success and warning.

As it appears on file.

Read-only.

Username is available.

Number looks incomplete — we could not verify it.

Focus

Focus the field to see the 2px offset ring.

Accessibility

  • `label` is wired to the control with `htmlFor`; required fields expose a visible marker plus an sr-only "(required)".
  • Helper text and messages are linked through `aria-describedby`; errors set `aria-invalid` and announce via `role="alert"`.
  • Disabled uses a muted surface; readonly keeps full contrast on a subtle surface, so the two are distinguishable without colour alone.

Input types

Typed wrappers over the same control, so keyboards, pickers and validation come from the platform while chrome and messaging stay identical.

import { EmailInput, DateInput, NumberInput } from "@/design-system";

Every supported type

Minimum 12 characters.

#006DEA
60%

Accessibility

  • Native types give mobile keyboards and platform pickers for free.
  • Colour and range values are always read back as text, never communicated by the swatch or track alone.

Multi-select

Typeahead multi-choice control that renders selections as removable chips, with an optional select-all row.

import { MultiSelect } from "@/design-system";

Multi-select

Olivia RhyePhoenix Baker

Selected people receive the handover note.

Accessibility

  • Each chip exposes a labelled remove button.
  • The listbox announces selected state per option; selection count is visible in the trigger.

Textarea

Multi-line field sharing the Input chrome, with an optional description, a politely-announced character counter and three sizes.

import { Textarea } from "@/design-system";

Textarea states and sizes

Visible to the family portal.

17 / 280 characters

Accessibility

  • The counter is an `aria-live="polite"` region, so it is announced without interrupting typing.
  • Vertical resize only — horizontal resize breaks the form grid.

Input icons

Input fields use a maximum of one supporting icon, positioned on the right. Left-side supporting icons are not used in the V2 input system.

import { Input, SearchInput, InputGroup } from "@/design-system";

When to use

  • Password (Eye / Eye-off), Email (Mail), URL (Link), Search (Search), Telephone (Phone).
  • Date, date & time, month and week (Calendar); time (Clock).
  • Any field where a single affordance clarifies the expected value or offers one action.

When not to use

  • Text, number and range fields — they stay icon-free; steppers and the range thumb are the control itself.
  • Colour fields — the swatch is the control; no second supporting icon.
  • Anywhere a native picker already draws its own calendar, clock or spinner affordance.

Icon configurations

Icon, spinner and clear share one slot.

The toggle is the field's one icon.

CL-

Do

  • Use at most one supporting icon per field, inside the field on the right.
  • Leave fields that need no affordance completely icon-free.
  • Let the clear control, spinner or visibility toggle occupy that single right slot.

Don't

  • Place a supporting icon on the left of an input.
  • Show a left and a right icon on the same field.
  • Stack two icons on the right, or repeat an icon the native control already provides.

Correct — one icon, right

Incorrect — do not build these

Accessibility

  • Decorative icons are `aria-hidden` and pointer-events-none, so they are never the only carrier of meaning.
  • Interactive affordances are real buttons with accessible names — the password toggle announces “Show password” / “Hide password”.
  • Icon size (--size-icon-sm), vertical centring and right padding are identical in every state, so position never shifts between default, focus, error, warning, success, read-only or disabled.

Value typography

Weight, style, case and alignment of the typed value, for data that is genuinely cased or numeric.

import { Input } from "@/design-system";

When to use

  • Reference codes shown uppercase, email addresses shown lowercase.
  • Money and quantities right-aligned so digits line up.
  • One emphasised value in a form that otherwise reads evenly.

When not to use

  • As decoration — emphasis loses meaning when every field has it.
  • To normalise data; casing on save is a data rule, not a visual one.

Weight, style, case and alignment

Do

  • Use uppercase or lowercase only where the data itself is cased that way — codes, emails.
  • Right-align numeric values so digits line up down a column.
  • Keep bold for a single value that carries the decision.

Don't

  • Bold or italicise every field — emphasis stops meaning anything.
  • Use a case transform to fix data that should be normalised on save.
  • Centre ordinary text; only short codes read well centred.

Accessibility

  • Case is a visual transform only — the stored and announced value is unchanged.
  • Alignment and weight never replace a label or a validation message.

Helper text emphasis

Helper copy can sit left, centred or right under a field, and step up to a tinted or solid label when the consequence must be noticed.

import { Field, FieldLabel, FieldHelperText } from "@/design-system";

When to use

  • Character counters aligned to the end of the field.
  • A visibility or consequence note that people routinely miss.

When not to use

  • Validation results — those belong in FieldMessage.
  • More than one emphasised helper per section.

Alignment and emphasis

Quiet supporting copy, aligned to the field.

0 / 240 characters

This field is visible to the resident's family.

Changing this re-issues every invitation.

Do

  • Keep the plain emphasis for almost every hint.
  • Right-align a helper only when it is a counter tied to the field's end.
  • Reserve solid emphasis for a consequence the person must not miss.

Don't

  • Use a tinted helper to report validation — that is FieldMessage.
  • Put more than one emphasised helper in the same form section.
  • Rely on the tint alone; the sentence must still say what happens.

Accessibility

  • Helper text stays associated with its control through aria-describedby.
  • Tone is never the only channel — the sentence states the consequence.
  • Solid and subtle tones both use token pairs that meet AA contrast in light and dark.

Labels, helper text & validation

Four message slots with one job each — and one rule: state is never colour-only.

Message slots and their intent.
SlotPropRendered asUse for
LabellabelFieldLabel + required / optional markerThe name of the field
DescriptiondescriptionHelper text above the controlContext needed before typing
Helper texthelperTextCaption below the controlFormat hints, consequences
ErrorerrorTextAlert icon + red caption, role=alertBlocking validation failure
WarningwarningTextTriangle icon + amber captionAccepted but questionable value
SuccesssuccessTextCheck icon + green captionConfirmed valid value

Format: CL-00000.

Postcode could not be verified.

Why messages carry an icon

WCAG 1.4.1 forbids colour as the only carrier of meaning. Every validation message pairs a token colour with an icon and explicit wording, so the state survives greyscale, low vision and colour-blind viewing.

Sizes

Small for dense tables and toolbars, medium as the default, large for focused single-task forms.

In context

A production form built only from the components above — no one-off styles.

New resident visit

Olivia Rhye

Everyone selected receives the visit summary.

Included in the family portal update.

0 / 280 characters

Do / Don't

Do

  • Give every field a visible label, and mark required fields with the built-in indicator.
  • Use the typed inputs (EmailInput, DateInput, NumberInput) so keyboards and pickers match the data.
  • Keep one size per form region — mixing sizes in one column breaks the rhythm.
  • Pair error colour with the icon and a sentence that says how to fix the value.

Don't

  • Don't replace a label with a placeholder — it disappears the moment typing starts.
  • Don't override height, padding or border colour with utility classes on a single instance.
  • Don't communicate an error with a red border only.
  • Don't disable a field to make it read-only — use `readOnly` so the value stays legible and copyable.