On this page
Text Field
A form field for accepting text inputs
- Overview
- Rules and guidance
- Properties
- Styles
- Accessibility
When to use
- When the user needs to input specific information that cannot be predicted from a predefined list, for instance their name
- When the input is memorable information that will be quicker to type by hand than interact with a more structured input
- When it is essential to avoid bias - predefined lists can force users to pick a choice they don't actually agree with
When not to use
- When only an item from a predefined list will be accepted - this is likely to result in an error. Use Radio, Checkbox, or Select Field instead.
- For large text inputs - users will not be able to see what they have entered easily. Use TextArea Field instead.
- To indicate that a field is unavailable - the disabled state is not supported. Use Summary List to show values that cannot be edited, or conditionally hide the field if it is not relevant in the current context.
Anatomy
- Label
- Hint
- Input
- Left icon - optional
- Right icon - optional
- Error message
- Required/Optional indicator
Basic usage
Edit live code
<TextField id="name" label="Name" />
Variants and features
Input types
TextField has four specialised variants for specific input types. These are separate components that share the TextField API.
- NumberField - for numeric input
- EmailField - for email addresses
- TelField - for telephone numbers
- PasswordField - for passwords. Characters are masked as the user types. Always provide hint text listing any requirements for the password format, such as the types of characters allowed.
Edit live code
<Stack spaceBetween={4}> <NumberField id="age-2" label="Age" characters={4} /> <EmailField id="email-types" label="Email address" characters={25} /> <TelField id="tel" label="Mobile" characters={11} /> <PasswordField id="password-types" label="Password" hint="At least 12 characters, including a number" characters={20} /> </Stack>
Left and right icons
Use the iconLeft or iconRight props to display an icon inside the input.
Edit live code
<Stack spaceBetween={4}> <TextField id="search-icon" label="Search accounts" iconLeft="search-empty" /> <TextField id="external-icon" label="Reference" iconRight="new-window" /> </Stack>
Common form features
The following features are shared across all Nebula form fields. See Form guidance for full detail.
Validation and errors - when a field is invalid, an error message appears below the input and the input border changes to indicate the error state.
Hint text - use the hint prop to provide additional context to help the user complete the field correctly. Keep hint text brief and specific to the field.
Required and optional - fields are required by default. Use the optional prop to mark a field as optional. The required or optional state is indicated visually as part of the label.
Field width - use the characters prop to set the input width to match the expected length of the content. Making inputs the right size for what they collect helps the user understand what to enter. TextField is responsive by default and displays full width below the smallest breakpoint - override with fullWidth="always" or fullWidth="never".
Edit live code
<Stack spaceBetween={4}> <TextField id="form-features-error" label="Account name" error="Enter an account name" /> <TextField id="form-features-hint" label="Account number" hint="8 digits, found at the top of your bill" /> <TextField id="form-features-optional" label="Middle name" optional /> <TextField id="form-features-width" label="Postcode" characters={8} /> </Stack>
Grouping
Text fields are typically part of a larger form. See the Form component and form guidelines for guidance on grouping and layout.
usage
- TextField must not be passed the disabled propThe prop passes through to the native input with no Nebula styling and removes the field from the tab order, making it invisible to keyboard users with no accessible indication of why.Copy rule ID for textfield.no-disabled
- TextField should not be used for text inputs that would cover multiple linesUsers may not be able to see their entire input. Use TextAreaField instead.Copy rule ID for textfield.no-multiline
- TextField should use a specialised variant when the input type is knownNumberField, EmailField, TelField, and PasswordField each set the correct input type, keyboard, and validation behaviour for their respective data types.Copy rule ID for textfield.use-specialised-variant
- TextField should use the characters prop to set input width to match the expected length of the contentAppropriately sized inputs help users understand what data is expected.Copy rule ID for textfield.character-width
- TextField icon should be used to add context to the input, not as decorationCopy rule ID for textfield.icon-not-decorative
- TextField should be replaced with plain text. For example in a SummaryList. When displaying a value the user cannot editA field that looks interactive but cannot be changed is confusing. Plain text communicates the value without implying editability.Copy rule ID for textfield.non-editable-as-text
content
- PasswordField hint text should list any requirements for the password format, such as character types allowedSetting clear expectations upfront helps users avoid errors when entering a password.Copy rule ID for textfield.hint-format-requirements
TextField
Also accepts all props from HTMLAttributes, InputHTMLAttributes.
| Name | Type | Default | Required | Description |
|---|---|---|---|---|
id | string | — | Yes | Unique id for the input, used to link the label, hint and error to it. Also used as the base for related ids such as `{id}-error`. |
error | ReactNode | — | No | Error message shown below the input. When set, the input gets `aria-invalid` and an error border, and the message is linked to it with `aria-describedby`. Takes precedence over an error provided by a surrounding `Form`. |
label | string | — | Yes | Visible label for the field. It is associated with the input, so it forms the input's accessible name. |
name | string | — | No | The `name` attribute passed to the input. Also used to look up the field's error from a surrounding `Form`. |
hint | ReactNode | — | No | Helper text shown below the label. It is part of the label element, so it is read as part of the input's accessible name. |
optional | boolean | false | No | Marks the field as not required. This appends "(optional)" to the label (or, when the theme marks required fields, hides the required asterisk) and sets `aria-required` on the input only when the field is not optional. |
characterLimit | number | — | No | Maximum number of characters, shown as a live "count/limit" counter below the input. The limit is advisory: it is not enforced on the input, but the counter turns to the error colour and screen readers are told how many characters remain or are over. |
fullWidth | always never small | 'small' | No | Controls when the field stretches to the full width of its container. `always` is always full width, `never` always uses the width set by `characters`, and `small` is full width on small screens only. |
characters | number | 25 | No | Width of the input, as an approximate number of characters (the width is set to `0.8em` per character, rounded up). Does not limit how much can be typed. |
affixWidth | number | 0 | No | Extra width in pixels added to the width calculated from `characters`, to make room for icons or buttons inside the input. |
iconLeft | IconName | (string & {}) | — | No | Name of an icon to show inside the left of the input. The input padding increases to make room for it. |
iconRight | IconName | (string & {}) | — | No | Name of an icon to show inside the right of the input. The input padding increases to make room for it. |
autoComplete | string | — | No | Hint to the browser's autofill, for example `email`. When the `disableAutocomplete` theme config flag is enabled this defaults to `off`; a value passed here overrides that. |
This component has no styles of its own to document.
In brief
Text Field is a native text input with a visible label. A screen reader announces the label (hint included), then the field, and reads an error as its description. Number Field, Tel Field, Email Field and Password Field are the same field with another input type.
What Nebula provides
- A real label linked to the input by id, so clicking the label focuses the input and gives a larger target.
- aria-required on the input unless the field is optional, which adds "(optional)" to the label. A required asterisk, when the theme shows one, is hidden from screen readers.
- An error sets aria-invalid on the input and links the message to it with aria-describedby. The message has an icon as well as colour.
- With characterLimit, the limit is the input's description and a live region announces the characters remaining once typing pauses.
Keyboard behaviour
The input is a native input, one tab stop reached with Tab, and it shows a focus ring when focus comes from the keyboard.
Interactions
- Tab - Moves focus to the input
Accessible design
Never use the placeholder as the label or the hint
A placeholder disappears as soon as the user types, and Nebula shows it at half opacity. Put the question in the label and any extra guidance in the hint.
WCAG: 3.3.2 Labels or Instructions
Keep the hint short
The hint sits inside the label element, so a screen reader reads it as part of the field's name. Put what the user needs first in the label and keep the hint to one short line.
WCAG: 3.3.2 Labels or Instructions
If several fields answer one question, group them under a shared label
Wrap them in a fieldset with a legend, as the Forms pattern describes, so a screen reader user hears what the group is for. A single field needs no group.
WCAG: 1.3.1 Info and Relationships
Write the error so it says what to change
"Enter a name" tells the user what to do and "Invalid" does not. The message is read with the field, so it has to make sense on its own.
WCAG: 3.3.3 Error Suggestion
Accessible development
Always pass errors through error, or through a Form with the field name
This is what sets aria-invalid and links the message to the input. Text placed beside the field is not announced with it.
WCAG: 3.3.1 Error Identification
If the field collects the user's own details, pass the matching autoComplete token
Use a token such as email or tel, so the browser and assistive technology can fill the field. A value passed here overrides the off default that the disableAutocomplete theme flag sets.
WCAG: 1.3.5 Identify Input Purpose
Accessibility testing status
Reviewed on 9 October 2026 against v17.0.1.
| Test | Status | Tested with |
|---|---|---|
| Default state | Tested | axe-core via the Storybook test runner (CI) |
| Advanced states | Partially tested | axe-core via the Storybook test runner (CI) |
| Keyboard navigation | Manually tested | keyboard (reported by the owner) |
| Screen reader | Partially tested | VoiceOver with Chrome (reported by the owner) |
What these tests and statuses mean
The table records which checks were run on this component on its own. It is not a statement of WCAG conformance, and it does not cover how the component is used.
The tests
- Default state: The component as it first appears, before anything is clicked or changed.
- Advanced states: Every other state and variant: error, open, selected, each size and style, and hovering.
- Keyboard navigation: Whether every function can be reached and used with the keyboard alone, with a visible focus ring.
- Screen reader: Whether a screen reader announces what is on screen correctly: the name, the role and any state.
The statuses
- Tested: Every check in this row passed in an automated run that repeats on every pull request.
- Manually tested: Every check in this row was run once, by a person or with a tool they started, and all of them passed. It is not re-run on every change.
- Partially tested: Some checks in this row were run once and passed; the rest are still to do.
- Issue found: A check in this row failed. The ticket is shown beside the status.
- Not tested: No check in this row has been run yet.
- Not applicable: This row does not apply to the component, for the reason given beside it.