Skip to content
EspañolEnglish
All components (204)

Text field

Fields · TextField · .amset-field

What it is and when to use it

The single-line field, with label, help text and error already wired up: the field itself sets the for/id and the aria-describedby, so there is no way to build it without an accessible relationship between the parts. Inside, it is a native <input>.

When to use it

  • Names, emails, references: any short text. With type="email", tel or url, the phone brings up the right keyboard.
  • front and back for an icon, a prefix or a unit inside the box.
  • numeric for digits that have to line up in a column (references, NIFs, typed dates).
  • readOnly for a piece of data that can be copied but not changed: the border becomes dashed.
  • inputRef to reach the real <input> (give it focus, measure it), not the box.

When not to

  • A number that is summed or has a minimum and maximum: NumberField.
  • More than one line: TextArea. A password: PasswordField.
  • A NIF, an IBAN, a phone number or a card: DocumentField, IbanField, PhoneField or CardField, which also validate them.
  • Choosing from a long list: SearchField.

Keyboard: Tab reaches the field and you type as in any input. Disabled, it leaves the Tab order; read-only, it can still be focused and copied.

Accessibility: the label is required; with hiddenLabel only the screen reader hears it, for when the surroundings already explain it. The help text and the error are read as the field's description. The required asterisk does not enter the name: it is conveyed with aria-required. With a finger, the box goes to 48 px and the font to 16 px, so the iPhone does not zoom the page.

Fine-tuning: CSS variables --amset-field-height, -padding, -font, -label, -description, -radius, -background and -border.

What it looks like

As it appears on the document
That email is already registered

<TextField label="First and last name" placeholder="Ada Lovelace" hint="As it appears on the document" />
<TextField label="Email" type="email" error="That email is already registered" />

Props

Import it with import { TextField } from '@amset/ui'. Required props are marked.

PropTypeWhat it does
labelrequiredstringRequired: a field without a visible label does not get into the library.
backReactNodeContent behind the text: a unit ("€"), a copy button.
classNamestring—
defaultValuestring—
disabledboolean—
errorstringError message. When it is passed, the field is marked as invalid.
frontReactNodeContent before the text: an icon, a prefix ("+34").
hiddenLabelbooleanThe label for the screen reader only. For when the field sits inside something that already explains itself (a table cell, a group of filters), never to save space.
hintstringPermanent hint text below the field. It does not replace the label.
inputRefRef<HTMLInputElement>The real `<input>`, to focus it, select its text or measure it from outside. It is separate from `ref` because the component paints a box with label, hint and error, and whoever asks for a ref almost always wants the control.
invalidboolean—
numericbooleanFixed-width digits (amounts, tax IDs, dates).
onChange(value: string) => void—
onChangeEvent(event: ChangeEvent<HTMLInputElement>) => voidLike `onChange`, but with the native event of the `<input>`: `e.target.value`, `e.currentTarget`... It exists to migrate a front end that already writes its handlers with the event (AMS-735). If you only want the text, `onChange` already gives it to you.
placeholderstring—
readOnlyboolean—
requiredboolean—
size"sm" | "md" | "lg"—
validationBehavior"aria" | "native"`aria` (the default) announces the state without the browser interrupting submission with its bubble; `native` also adds its own validation.
valuestring—
variantFieldVariant—

It also accepts the attributes of the element it renders: className, style, data-*, aria-* and its events.

CSS variables

These CSS variables are how you adapt it. Declare them on the component's selector, not on :root: the stylesheet redeclares them in the rule itself, and a declaration on the same element always wins.

VariableDefault
--amset-field-heightvar(--amset-height-control)
--amset-field-paddingvar(--amset-space-3)
--amset-field-fontvar(--amset-text-base)
--amset-field-labelvar(--amset-text-sm)
--amset-field-descriptionvar(--amset-text-sm)
--amset-field-radiusvar(--amset-radius)
--amset-field-backgroundvar(--amset-surface)
--amset-field-bordervar(--amset-border-bold)
--amset-field-familyvar(--amset-font)
--amset-field-shadowvar(--amset-shadow-1)
--amset-field-gapvar(--amset-space-1)
--amset-field-label-linevar(--amset-line-tight)
--amset-field-inkvar(--amset-ink)
--amset-field-label-colorinherit
--amset-field-label-familyinherit
--amset-field-label-weightvar(--amset-weight-medium)
--amset-field-label-transformnone
--amset-field-label-spacingnormal
--amset-field-required-displayinline
--amset-field-focus-shadow0 0 0 1px var(--amset-focus)

How to change it

.amset-field {
  --amset-field-height: ...;
  --amset-field-padding: ...;
}

In the test bench

Every state and variant, to try one at a time, on its page at ui.amset.tech: