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",telorurl, the phone brings up the right keyboard. frontandbackfor an icon, a prefix or a unit inside the box.numericfor digits that have to line up in a column (references, NIFs, typed dates).readOnlyfor a piece of data that can be copied but not changed: the border becomes dashed.inputRefto 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,PhoneFieldorCardField, 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
<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.
| Prop | Type | What it does |
|---|---|---|
labelrequired | string | Required: a field without a visible label does not get into the library. |
back | ReactNode | Content behind the text: a unit ("€"), a copy button. |
className | string | — |
defaultValue | string | — |
disabled | boolean | — |
error | string | Error message. When it is passed, the field is marked as invalid. |
front | ReactNode | Content before the text: an icon, a prefix ("+34"). |
hiddenLabel | boolean | The 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. |
hint | string | Permanent hint text below the field. It does not replace the label. |
inputRef | Ref<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. |
invalid | boolean | — |
numeric | boolean | Fixed-width digits (amounts, tax IDs, dates). |
onChange | (value: string) => void | — |
onChangeEvent | (event: ChangeEvent<HTMLInputElement>) => void | Like `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. |
placeholder | string | — |
readOnly | boolean | — |
required | boolean | — |
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. |
value | string | — |
variant | FieldVariant | — |
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.
| Variable | Default |
|---|---|
--amset-field-height | var(--amset-height-control) |
--amset-field-padding | var(--amset-space-3) |
--amset-field-font | var(--amset-text-base) |
--amset-field-label | var(--amset-text-sm) |
--amset-field-description | var(--amset-text-sm) |
--amset-field-radius | var(--amset-radius) |
--amset-field-background | var(--amset-surface) |
--amset-field-border | var(--amset-border-bold) |
--amset-field-family | var(--amset-font) |
--amset-field-shadow | var(--amset-shadow-1) |
--amset-field-gap | var(--amset-space-1) |
--amset-field-label-line | var(--amset-line-tight) |
--amset-field-ink | var(--amset-ink) |
--amset-field-label-color | inherit |
--amset-field-label-family | inherit |
--amset-field-label-weight | var(--amset-weight-medium) |
--amset-field-label-transform | none |
--amset-field-label-spacing | normal |
--amset-field-required-display | inline |
--amset-field-focus-shadow | 0 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:
