Live code
Storybook
Usage
TextField
TextField enables the user to type in text information. It has an input, a label, and optional helper text. It supports several input types like text and password. It can be disabled or have a validation state. The label can be hidden or shown while the field remains correctly marked as required.
Usage
Basic
<TextField id="text-field-default" label="Label" name="textFieldDefault" />
Advanced
<TextField
hasValidationIcon
helperText="custom helper text"
id="text-field-advanced"
isRequired
label="Label"
name="textFieldAdvanced"
placeholder="Placeholder"
type="text"
size="large"
validationState="danger"
validationText="validation failed"
/>
Password Toggle
<TextField
hasPasswordToggle
id="text-field-password-toggle"
isRequired
label="Password"
name="textFieldPasswordToggle"
placeholder="Placeholder"
validationState="danger"
validationText="validation failed"
/>
InputAddon
Use InputAddon with startAddon and endAddon to render non-input content inside the same input row. Addons are rendered as provided. For consistent spacing, sizing, and alignment with the input, use InputAddon as the wrapper for icon, symbol, and control content.
InputAddon resolves size from field context, so nested Icon and ControlButton components use that resolved addon size by default.
For non-interactive icon or symbol addons rendered as label, decide whether the visible content is decorative or semantic:
- Decorative content: keep it aria-hidden="true" and include descriptive hidden text.
- Semantic content: keep it exposed and do not force aria-hidden.
Label-Based Search Addon
<TextField
id="text-field-addon-search"
label="Search"
name="textFieldAddonSearch"
placeholder="Search"
startAddon={
<InputAddon elementType="label" htmlFor="text-field-addon-search">
<Icon name="search" />
<VisuallyHidden>Use search to find jobs for you</VisuallyHidden>
</InputAddon>
}
/>
Interactive End Addon
<TextField
id="text-field-addon-clear"
label="Search"
name="textFieldAddonClear"
placeholder="Search"
defaultValue="Filled"
endAddon={
<InputAddon>
<ControlButton isSymmetrical isSubtle>
<Icon name="close" />
<VisuallyHidden>Clear</VisuallyHidden>
</ControlButton>
</InputAddon>
}
/>
Do not use elementType="label" when the addon wraps an interactive element such as a button or link.
Multiple Addons
<TextField
id="text-field-addon-multiple"
label="Username"
name="textFieldAddonMultiple"
placeholder="spirit-design-system"
size="large"
startAddon={
<>
<InputAddon elementType="label" htmlFor="text-field-addon-multiple">
<Icon name="link" />
<VisuallyHidden>Profile URL</VisuallyHidden>
</InputAddon>
<InputAddon elementType="label" htmlFor="text-field-addon-multiple">
<span aria-hidden="true">@</span>
<VisuallyHidden>Insert your username without the @ symbol</VisuallyHidden>
</InputAddon>
</>
}
endAddon={
<InputAddon>
<ControlButton isSymmetrical isSubtle>
<Icon name="close" />
<VisuallyHidden>Clear</VisuallyHidden>
</ControlButton>
</InputAddon>
}
/>
API
| Name | Type | Default | Required | Description |
|---|---|---|---|---|
| autoComplete | string | — | ✕ | Automated assistance in filling |
| endAddon | ReactNode | — | ✕ | Addon rendered after the input |
| hasPasswordToggle | bool | — | ✓ | If true, the type is set to password and a password toggle is shown |
| hasValidationIcon | bool | false | ✕ | Whether to show validation icon |
| helperText | string | — | ✕ | Custom helper text |
| id | string | — | ✓ | Input and label identification |
| inputWidth | number | — | ✕ | Input width |
| isDisabled | bool | — | ✕ | Whether is field disabled |
| isLabelHidden | bool | — | ✕ | Whether is label hidden |
| isRequired | bool | — | ✕ | Whether is field required |
| label | ReactNode | — | ✓ | Label text |
| name | string | — | ✕ | Input name |
| pattern | string | — | ✕ | Defines regular expressions for allowed value types |
| placeholder | string | — | ✕ | Input placeholder |
| ref | ForwardedRef<HTMLInputElement> | — | ✕ | Input element reference |
| size | Size dictionary | medium | ✕ | Size variant |
| startAddon | ReactNode | — | ✕ | Addon rendered before the input |
| type | [email | number | password | search | tel | text | url] | text | ✕ | Input type |
| validationState | Validation dictionary | — | ✕ | Type of validation state |
| validationText | [ReactNode | ReactNode[]] | — | ✕ | Validation text |
| value | string | — | ✕ | Input value * |
| variant | Fill Variants dictionary | fill | ✕ | InputContainer variant |
(*) When value is provided, the component acts as an controlled component and requires an native onChange handler to update the value. For more information, please read React documentation
On top of the API options, the components accept additional attributes. If you need more control over the styling of a component, you can use style props and escape hatches.
Custom Component
Text field classes are fabricated using useTextFieldStyleProps hook. You can use it to create your own custom TextField component.
const CustomTextField = (props: SpiritTextFieldProps): JSX.Element => {
const { classProps, props: modifiedProps } = useTextFieldStyleProps(props);
return (
<div className={classProps.root}>
<input {...modifiedProps} className={classProps.input} />
<label htmlFor={props.id} className={styleProps.label}>
{props.label}
</label>
</div>
);
};
For detailed information see TextField component.