Reference version

TextField

A SwiftUI TextField component for text input.

iOS
tvOS
Included in Expo Go
Bundled version:
~56.0.2

For the complete documentation index, see llms.txt. Use this file to discover all available pages.

Expo UI TextField matches the official SwiftUI TextField API and supports single-line and multiline input, keyboard configuration, submit handling, and an imperative ref for programmatic control.

Installation

Terminal
npx expo install @expo/ui

If you are installing this in an existing React Native app, make sure to install expo in your project.

Usage

Basic text field

BasicTextFieldExample.tsx
import { useState } from 'react'; import { Host, TextField } from '@expo/ui/swift-ui'; export default function BasicTextFieldExample() { const [value, setValue] = useState(''); return ( <Host matchContents> <TextField placeholder="Username" onTextChange={setValue} /> </Host> ); }

Multiline text field

Set axis="vertical" to allow the text field to expand vertically. Use the lineLimit modifier to control the visible line count. When using Host matchContents, add fixedSize({ horizontal: false, vertical: true }) so the text field accepts the parent's width while using its ideal height.

MultilineTextFieldExample.tsx
import { useState } from 'react'; import { Host, TextField } from '@expo/ui/swift-ui'; import { lineLimit, fixedSize } from '@expo/ui/swift-ui/modifiers'; export default function MultilineTextFieldExample() { const [value, setValue] = useState(''); return ( <Host matchContents> <TextField axis="vertical" placeholder="Tell us about yourself..." onTextChange={setValue} modifiers={[lineLimit(5), fixedSize({ horizontal: false, vertical: true })]} /> </Host> ); }

Keyboard type

Use the keyboardType modifier to display a specific keyboard layout.

KeyboardTypeExample.tsx
import { useState } from 'react'; import { Host, TextField } from '@expo/ui/swift-ui'; import { keyboardType, autocorrectionDisabled } from '@expo/ui/swift-ui/modifiers'; export default function KeyboardTypeExample() { const [value, setValue] = useState(''); return ( <Host matchContents> <TextField placeholder="Email" onTextChange={setValue} modifiers={[keyboardType('email-address'), autocorrectionDisabled()]} /> </Host> ); }

Submit handling

Use the submitLabel modifier to customize the return key and onSubmit to handle the submit action.

SubmitHandlingExample.tsx
import { useState } from 'react'; import { Host, TextField } from '@expo/ui/swift-ui'; import { submitLabel, onSubmit } from '@expo/ui/swift-ui/modifiers'; export default function SubmitHandlingExample() { const [value, setValue] = useState(''); return ( <Host matchContents> <TextField placeholder="Search..." onTextChange={setValue} modifiers={[submitLabel('search'), onSubmit(() => console.log('Submitted:', value))]} /> </Host> ); }

Imperative ref

Use a ref to imperatively set text, focus, blur, or select text.

Note: setSelection requires iOS 18.0+ / tvOS 18.0+. The other ref methods work on all supported versions.

ImperativeRefExample.tsx
import { useRef } from 'react'; import { Host, TextField, TextFieldRef, Button, HStack, VStack, useNativeState, } from '@expo/ui/swift-ui'; import { buttonStyle } from '@expo/ui/swift-ui/modifiers'; export default function ImperativeRefExample() { const ref = useRef<TextFieldRef>(null); const text = useNativeState('Select me!'); return ( <Host matchContents> <VStack> <TextField ref={ref} text={text} placeholder="Imperative field" /> <HStack spacing={12}> <Button modifiers={[buttonStyle('bordered')]} onPress={() => ref.current?.focus()} label="Focus" /> <Button modifiers={[buttonStyle('bordered')]} onPress={() => ref.current?.blur()} label="Blur" /> <Button modifiers={[buttonStyle('bordered')]} onPress={() => ref.current?.setText('SwiftUI rocks!')} label="Set Text" /> <Button modifiers={[buttonStyle('bordered')]} onPress={() => ref.current?.clear()} label="Clear" /> <Button modifiers={[buttonStyle('bordered')]} onPress={() => ref.current?.setSelection(0, 7)} label="Select" /> </HStack> </VStack> </Host> ); }

Worklet text masking

When onTextChange is marked with the 'worklet' directive, it runs synchronously on the UI thread, so writes to useNativeState observables inside the callback take effect before the next frame. There is no flicker between the typed text and the masked text. The example below masks a phone number as the user types and writes both text and selection from the worklet to keep the cursor at the end of the formatted value.

Note: Worklets require installing react-native-reanimated and react-native-worklets. The selection prop requires iOS 18.0+ / tvOS 18.0+. On older versions the worklet can still update the text but cursor positioning is unavailable.

WorkletPhoneMaskExample.tsx
import { Host, TextField, useNativeState } from '@expo/ui/swift-ui'; import { keyboardType } from '@expo/ui/swift-ui/modifiers'; export default function WorkletPhoneMaskExample() { const phone = useNativeState(''); const selection = useNativeState({ start: 0, end: 0 }); return ( <Host matchContents> <TextField text={phone} selection={selection} placeholder="(555) 123-4567" modifiers={[keyboardType('phone-pad')]} onTextChange={v => { 'worklet'; const digits = v.replace(/\D/g, '').slice(0, 10); let formatted = digits; if (digits.length > 6) { formatted = `(${digits.slice(0, 3)}) ${digits.slice(3, 6)}-${digits.slice(6)}`; } else if (digits.length > 3) { formatted = `(${digits.slice(0, 3)}) ${digits.slice(3)}`; } if (formatted !== v) { phone.value = formatted; selection.value = { start: formatted.length, end: formatted.length }; } }} /> </Host> ); }

API

import { TextField } from '@expo/ui/swift-ui';

Component

TextField

iOS
tvOS

Type: React.Element<TextFieldProps>

Renders a SwiftUI TextField.

TextFieldProps

autoFocus

iOS
tvOS
Optional • Type: boolean • Default: false

If true, the text field will be focused automatically when mounted.

axis

iOS
tvOS
Optional • Literal type: string • Default: 'horizontal'

The axis along which the text field grows when content exceeds a single line.

  • 'horizontal' — single line (default).
  • 'vertical' — expands vertically for multiline content. Use lineLimit modifier to cap visible lines.

Acceptable values are: 'horizontal' | 'vertical'

children

iOS
tvOS
Optional • Type: React.ReactNode

Slot children — supports <TextField.Placeholder> with a <Text> child (any text-styling modifiers on that Text are preserved as the placeholder's styling).

maxLength

iOS
tvOS
Optional • Type: number

Maximum number of characters allowed. Truncates natively as the user types.

onFocusChange

iOS
tvOS
Optional • Type: (focused: boolean) => void

A callback triggered when the field gains or loses focus.

onSelectionChange

iOS 18.0+ tvos 18.0+
Optional • Type: (selection: { end: number, start: number }) => void

A callback triggered when the text selection range changes.

onTextChange

iOS
tvOS
Optional • Type: (text: string) => void

A callback triggered when the text value changes.

If the callback is marked with the 'worklet' directive, it runs synchronously on the UI thread; otherwise it is delivered asynchronously as a regular JS event.

placeholder

iOS
tvOS
Optional • Type: string

A text that is displayed when the field is empty.

ref

iOS
tvOS
Optional • Type: Ref<TextFieldRef>

selection

iOS 18.0+ tvos 18.0+
Optional • Type: ObservableState<TextFieldSelection>

Observable state the field writes the current selection to. Create with useNativeState<TextFieldSelection>({ start: 0, end: 0 }). Use ref.setSelection(start, end) to set programmatically.

text

iOS
tvOS
Optional • Type: ObservableState<string>

An observable state that holds the current text. Create one with useNativeState('') or useNativeState('initial value'). If omitted, the field manages its own internal state.

Types

ObservableState

iOS
tvOS

Observable state shared between JavaScript and native views (Jetpack Compose on Android and SwiftUI on iOS).

Type: SharedObject extended by:

PropertyTypeDescription
valueT

The current value. Reads are safe from any thread; prefer writing from a worklet so the update runs on the native UI thread. Updating state from the JS thread might show a development warning.

TextFieldRef

iOS
tvOS

Can be used for imperatively focusing and setting text/selection on the TextField component.

PropertyTypeDescription
blur() => Promise<void>
-
clear() => Promise<void>

Clear the current text.

focus() => Promise<void>
-
setSelection(start: number, end: number) => Promise<void>
Only for:
iOS 18.0+ tvos 18.0+

Programmatically set the selection range.

setText(newText: string) => Promise<void>
-

TextFieldSelection

iOS
tvOS

Selection range — start and end are character offsets into the field's text.

PropertyTypeDescription
endnumber
-
startnumber
-