Pre-alphaThe registry and the CLI are not published yet.Roadmap

Input

A text control with a prefix and a suffix. Field adds the label, description and error around it.

Edit profile

Done

Name
Katherine Johnson
Username
@kjohnson
Letters, numbers and underscores.
Website
nasa gov
Enter a valid URL.
Member since
June 1953

Installation

npx axiom add input
pnpm dlx axiom add input
yarn dlx axiom add input
bun x axiom add input

Also copies field.tsx, the Field parts shared with TextArea and DatePicker, and use-input.ts, which holds the value, focus and accessibility logic.

To keep a focused field above the keyboard in a long form, put the form in a KeyboardAwareScrollView from react-native-keyboard-controller.

Usage

import { Field, Input } from "@/components/ui/input";

<Field>
	<Field.Label>Email</Field.Label>
	<Input value={email} onChangeText={setEmail} />
	<Field.Description>We'll never share it.</Field.Description>
</Field>;

Input is the control alone: the box, the text, the prefix and the suffix. The label and the messages are Field parts you place yourself, above, below or next to the control, in any order. Without a Field, give the input an accessibilityLabel:

<Input placeholder="Search" accessibilityLabel="Search" />

Props

Input

Input accepts every TextInput prop from React Native (keyboardType, autoComplete, secureTextEntry, returnKeyType…) on top of these:

PropTypeDefaultDescription
valuestring—Current text. Use with onChangeText for a controlled field.
defaultValuestring''Initial text when the field manages its own value.
onChangeText(text: string) => void—Called on every change.
placeholderstring—Hint shown while the field is empty, in content.subtle. Don’t use it as the label.
prefixReactNode—Content before the text: an icon, a currency sign, a country code.
suffixReactNode—Content after the text: a unit, a clear button, a visibility toggle.
size'sm' | 'md' | 'lg''md'Fixed height from the input size tokens: 50, 56 or 64pt.
variant'outline' | 'filled''outline'outline has a border, filled a subtle background with no border.
invalidboolean—Red border. Inside a Field, it follows the Field.
disabledboolean—Read-only with the disabled tokens. Maps to editable={false}. Inside a Field, it follows the Field.
onFocus / onBlur(event) => void—Called when the field gains or loses focus. The focused border is handled for you.
refRef<TextInput>—Gives access to focus(), blur() and clear(), to chain fields on submit.
containerStyleStyleProp<ViewStyle>—Styles for the box around the text. style goes to the TextInput.

Field

PartWhat it is
FieldA View that stacks its children with a gap. Takes invalid, disabled and required.
Field.LabelThe label. With required, it ends with a red *.
Field.DescriptionHelp under the control, in the muted color.
Field.ErrorThe error, in red. Rendering it puts the field in the invalid state: render it only on an error.

Field passes invalid, disabled and required to the control inside it. When a part’s children are plain text, the control announces them itself: the label as its accessibility label, the error (or else the description) as its hint, and “Required” when it applies. The parts are then hidden from screen readers so nothing is read twice.

Colors come from input.{outline,filled}.{default,focused,invalid,disabled} in the component tokens.

Use cases

Login form

autoComplete and keyboardType give the right keyboard and password autofill; the eye button is a suffix.

Welcome back
Password
••••••••

Sign in

<Field required>
	<Field.Label>Email</Field.Label>
	<Input keyboardType="email-address" autoComplete="email" autoCapitalize="none" />
</Field>
<Field>
	<Field.Label>Password</Field.Label>
	<Input
		secureTextEntry={!visible}
		autoComplete="current-password"
		suffix={<IconButton icon="eye" size="sm" accessibilityLabel="Show password" onPress={toggle} />}
	/>
</Field>

Validation on blur

Show the error once the user leaves the field, not while they are still typing.

Shipping
Street
221B Baker Street
Postcode
NW1
Postcodes look like NW1 6XE.
City
Lon
<Field>
	<Field.Label>Postcode</Field.Label>
	<Input
		value={postcode}
		onChangeText={setPostcode}
		onBlur={() => setTouched(true)}
	/>
	{touched && !isPostcode(postcode) ? (
		<Field.Error>Postcodes look like NW1 6XE.</Field.Error>
	) : null}
</Field>

Amount with a prefix and a unit

prefix and suffix hold what the user doesn’t type. The value stays a plain number.

Send money

MH

Margaret Hamilton@mhamilton
Amount
$

120.00

USD
Balance: $1,240.18
Note
What’s it for?
<Field>
	<Field.Label>Amount</Field.Label>
	<Input size="lg" keyboardType="decimal-pad" prefix="$" suffix="USD" />
	<Field.Description>Balance: {balance}</Field.Description>
</Field>

Chain fields with the return key

returnKeyType="next" and a ref move focus to the next field, so the user never has to reach for it.

First name
Dennis
Last name
Rit
qwertyuiopasdfghjkl

next

const lastName = useRef<TextInput>(null);

<Field>
	<Field.Label>First name</Field.Label>
	<Input returnKeyType="next" onSubmitEditing={() => lastName.current?.focus()} />
</Field>
<Field>
	<Field.Label>Last name</Field.Label>
	<Input ref={lastName} returnKeyType="done" />
</Field>