Skip to Content

Form Components

Input controls and form utilities for building data entry interfaces. All form components support labels, error states, and size variants, and integrate seamlessly with react-hook-form via the FormField wrapper.

import { Input, TextArea, Select, Checkbox, Switch, RadioGroup, SegmentedControl, SearchBar, FormField, } from '@/common/components';

Input

A text input field with label, error/helper text, and optional left/right icon slots. Automatically toggles password visibility when secureTextEntry is set. Extends React Native’s TextInputProps.

Basic Usage

<Input label="Email" placeholder="you@example.com" />

With Error and Helper Text

<Input label="Username" error="Username is already taken" /> <Input label="Password" helperText="Must be at least 8 characters" secureTextEntry />

With Icons

import { Icon } from '@/common/components'; <Input label="Search" placeholder="Type to search..." leftIcon={<Icon name="search-outline" size={18} variant="muted" />} /> <Input label="Email" rightIcon={<Icon name="checkmark-circle" size={18} variant="accent" />} value="valid@email.com" />

Password Input

When secureTextEntry is set, a toggle eye icon is automatically rendered in the right icon slot.

<Input label="Password" secureTextEntry placeholder="Enter password" />

Sizes

<Input label="Small" size="sm" /> <Input label="Medium" size="md" /> <Input label="Large" size="lg" />

Props

PropTypeDefaultDescription
labelstringLabel text above the input
errorstringError message below the input (takes precedence over helperText)
helperTextstringHelper text below the input
disabledbooleanfalseDisable the input
size'sm' | 'md' | 'lg''md'Size variant
leftIconReactNodeIcon rendered on the left side
rightIconReactNodeIcon rendered on the right side (replaced by password toggle when secureTextEntry is set)

Input extends TextInputProps, so you can use placeholder, keyboardType, autoCapitalize, onChangeText, value, and all other standard text input props.


TextArea

A multi-line text input with optional character count display. Extends Input props (excluding secureTextEntry).

Basic Usage

<TextArea label="Description" placeholder="Enter a description..." />

With Character Count

<TextArea label="Bio" maxLength={280} showCount placeholder="Tell us about yourself..." />

Custom Lines

<TextArea label="Notes" numberOfLines={6} />

Props

PropTypeDefaultDescription
numberOfLinesnumber4Number of visible text lines
maxLengthnumberMaximum character count
showCountbooleanfalseDisplay character counter below the field

Plus all Input props except secureTextEntry.


Select

A dropdown picker that opens a bottom sheet with selectable options.

Basic Usage

const [value, setValue] = useState(''); <Select label="Country" placeholder="Select a country" value={value} onChange={setValue} options={[ { label: 'United States', value: 'us' }, { label: 'United Kingdom', value: 'uk' }, { label: 'Germany', value: 'de' }, ]} />

With Error and Disabled Options

<Select label="Plan" value={plan} onChange={setPlan} error="Please select a plan" options={[ { label: 'Free', value: 'free' }, { label: 'Pro', value: 'pro' }, { label: 'Enterprise (Coming Soon)', value: 'enterprise', disabled: true }, ]} />

SelectOption Type

interface SelectOption { label: string; value: string; disabled?: boolean; }

Props

PropTypeDefaultDescription
valuestringrequiredCurrently selected option value
onChange(value: string) => voidrequiredCallback with the new selected value
optionsSelectOption[]requiredArray of selectable options
placeholderstringPlaceholder text when no option is selected
labelstringLabel text above the select
errorstringError message below the select
disabledbooleanfalseDisable the select
size'sm' | 'md' | 'lg''md'Size variant

Checkbox

A toggle checkbox with optional label text and indeterminate state support.

Basic Usage

const [checked, setChecked] = useState(false); <Checkbox checked={checked} onChange={setChecked} label="I agree to the terms" />

Indeterminate State

Used for “select all” checkboxes when some items are selected.

<Checkbox checked={allSelected} indeterminate={someSelected && !allSelected} onChange={handleSelectAll} label="Select All" />

Sizes

<Checkbox checked label="Small" size="sm" onChange={() => {}} /> <Checkbox checked label="Medium" size="md" onChange={() => {}} /> <Checkbox checked label="Large" size="lg" onChange={() => {}} />

Props

PropTypeDefaultDescription
checkedbooleanrequiredWhether the checkbox is checked
onChange(checked: boolean) => voidrequiredCallback with the new checked value
labelstringText label beside the checkbox
disabledbooleanfalseDisable the checkbox
indeterminatebooleanfalseShow mixed/indeterminate state
size'sm' | 'md' | 'lg''md'Size variant

Switch

An on/off toggle with optional label text.

Basic Usage

const [enabled, setEnabled] = useState(false); <Switch value={enabled} onValueChange={setEnabled} label="Enable notifications" />

Without Label

<Switch value={darkMode} onValueChange={toggleDarkMode} />

Props

PropTypeDefaultDescription
valuebooleanrequiredCurrent on/off state
onValueChange(value: boolean) => voidrequiredToggle callback
labelstringText label beside the switch
disabledbooleanfalseDisable the switch
size'sm' | 'md' | 'lg''md'Size variant

RadioGroup

A single-select option group supporting vertical and horizontal layouts.

Vertical Layout (Default)

const [value, setValue] = useState('email'); <RadioGroup value={value} onChange={setValue} options={[ { label: 'Email', value: 'email' }, { label: 'SMS', value: 'sms' }, { label: 'Push Notification', value: 'push' }, ]} />

Horizontal Layout

<RadioGroup value={size} onChange={setSize} orientation="horizontal" options={[ { label: 'S', value: 'sm' }, { label: 'M', value: 'md' }, { label: 'L', value: 'lg' }, { label: 'XL', value: 'xl' }, ]} />

With Disabled Options

<RadioGroup value={plan} onChange={setPlan} options={[ { label: 'Free', value: 'free' }, { label: 'Pro', value: 'pro' }, { label: 'Enterprise (Contact Us)', value: 'enterprise', disabled: true }, ]} />

RadioOption Type

interface RadioOption { label: string; value: string; disabled?: boolean; }

Props

PropTypeDefaultDescription
valuestringrequiredCurrently selected option value
onChange(value: string) => voidrequiredCallback with the new selected value
optionsRadioOption[]requiredArray of radio options
orientation'vertical' | 'horizontal''vertical'Layout direction
size'sm' | 'md' | 'lg''md'Size variant

SegmentedControl

An animated tab-style selector. Each segment can optionally include an icon alongside its label.

Basic Usage

const [value, setValue] = useState('list'); <SegmentedControl value={value} onChange={setValue} options={[ { label: 'List', value: 'list' }, { label: 'Grid', value: 'grid' }, ]} />

With Icons

import { Icon } from '@/common/components'; <SegmentedControl value={view} onChange={setView} options={[ { label: 'List', value: 'list', icon: <Icon name="list-outline" size={16} /> }, { label: 'Grid', value: 'grid', icon: <Icon name="grid-outline" size={16} /> }, { label: 'Map', value: 'map', icon: <Icon name="map-outline" size={16} /> }, ]} />

SegmentOption Type

interface SegmentOption { label: string; value: string; icon?: ReactNode; }

Props

PropTypeDefaultDescription
valuestringrequiredCurrently selected segment value
onChange(value: string) => voidrequiredCallback when a segment is selected
optionsSegmentOption[]requiredArray of segment options
size'sm' | 'md''md'Size variant
disabledbooleanfalseDisable all segments

The active segment indicator animates smoothly between options using React Native’s Animated API.


A search input with a built-in search icon, clear button, and optional loading indicator.

Basic Usage

const [query, setQuery] = useState(''); <SearchBar value={query} onChangeText={setQuery} placeholder="Search products..." />

With Submit and Clear Handlers

<SearchBar value={query} onChangeText={setQuery} onSubmit={handleSearch} onClear={handleClear} placeholder="Search..." />

Loading State

Replaces the clear button with a spinner while search results are being fetched.

<SearchBar value={query} onChangeText={setQuery} loading={isSearching} placeholder="Search..." />

Props

PropTypeDefaultDescription
valuestringrequiredCurrent search text
onChangeText(text: string) => voidrequiredText change handler
placeholderstringPlaceholder text
onSubmit() => voidCallback when the user submits (presses return)
onClear() => voidCallback when the clear button is pressed
loadingbooleanfalseShow a spinner instead of the clear button
autoFocusbooleanfalseFocus the input on mount
size'sm' | 'md' | 'lg''md'Size variant

FormField

A wrapper component that connects any input to react-hook-form’s Controller. It automatically passes value, onChangeText, onBlur, label, and error props to its child input via cloneElement.

Basic Usage

import { useForm } from 'react-hook-form'; import { zodResolver } from '@hookform/resolvers/zod'; import { z } from 'zod'; const schema = z.object({ email: z.string().email(), password: z.string().min(8), }); type FormData = z.infer<typeof schema>; function LoginForm() { const { control, handleSubmit } = useForm<FormData>({ resolver: zodResolver(schema), }); return ( <> <FormField name="email" control={control} label="Email" required> <Input placeholder="you@example.com" keyboardType="email-address" /> </FormField> <FormField name="password" control={control} label="Password" required> <Input placeholder="Enter password" secureTextEntry /> </FormField> <Button title="Sign In" onPress={handleSubmit(onSubmit)} /> </> ); }

With Other Input Types

FormField works with any input component that accepts value/onChangeText props.

<FormField name="bio" control={control} label="Bio"> <TextArea placeholder="Tell us about yourself" maxLength={280} showCount /> </FormField> <FormField name="country" control={control} label="Country" required> <Select placeholder="Select a country" options={countries} /> </FormField>

Props

PropTypeDefaultDescription
nameFieldPath<T>requiredField path within the form values object
controlControl<T>requiredreact-hook-form control object
labelstringLabel prepended to the child input
requiredbooleanWhen true, appends * to the label
childrenReactElementrequiredInput element that receives form controller props

FormField uses React.cloneElement to inject props into its child. The child component must accept value, onChangeText, onBlur, label, and error props for the integration to work correctly.

Last updated on