alouette
Version:
A modern, customizable design system built on top of NativeWind v5 with configurable defaults
209 lines (161 loc) • 8.41 kB
Markdown
---
name: alouette-inputs
description: >
The controls that take a value from the user. InputText is the text field,
whose mode sets the keyboard, autocomplete and secure entry together;
TextArea is its multiline twin, InputPassword adds the show/hide toggle, and
InputCode is a one-time code (never a row of InputTexts). Switch applies a
setting at once; a standalone Checkbox is a form opt-in. Select picks one
value from a known list and InputTextAutocomplete narrows that list by
typing. Single-select groups compose their children, never an options array:
RadioGroup (a list), RadioButtonGroup (a segmented pill, behind the
light/dark ColorModePicker) and RadioCardGroup (cards); multi-select
CheckboxGroup and CheckboxCardGroup. A choice that moves between routes is
navigation, not a radio group. Binding these to a validated form is
alouette-forms. Load when adding a text field, a password or code field, a
dropdown, a toggle, checkboxes, radio buttons, a segmented choice, or a
light/dark switch.
sources:
- packages/alouette/src/ui/inputs/InputText.tsx
- packages/alouette/src/ui/inputs/InputPassword.tsx
- packages/alouette/src/ui/inputs/InputCode.tsx
- packages/alouette/src/ui/inputs/InputCode.stories.tsx
- packages/alouette/src/ui/inputs/Select.shared.tsx
- packages/alouette/src/ui/inputs/Select.tsx
- packages/alouette/src/ui/inputs/Select.web.tsx
- packages/alouette/src/ui/inputs/InputTextAutocomplete.shared.tsx
- packages/alouette/src/ui/inputs/InputTextAutocomplete.tsx
- packages/alouette/src/ui/inputs/InputTextAutocomplete.web.tsx
- packages/alouette/src/ui/inputs/InputTextAutocomplete.stories.tsx
- packages/alouette/src/ui/inputs/TextArea.tsx
- packages/alouette/src/ui/inputs/Switch.tsx
- packages/alouette/src/ui/inputs/Switch.web.tsx
- packages/alouette/src/ui/inputs/RadioGroup.tsx
- packages/alouette/src/ui/inputs/Radio.tsx
- packages/alouette/src/ui/inputs/RadioButtonGroup.tsx
- packages/alouette/src/ui/inputs/RadioButton.tsx
- packages/alouette/src/ui/inputs/RadioCardGroup.tsx
- packages/alouette/src/ui/inputs/RadioCard.tsx
- packages/alouette/src/ui/inputs/RadioCardGroup.stories.tsx
- packages/alouette/src/ui/inputs/CheckboxGroup.tsx
- packages/alouette/src/ui/inputs/Checkbox.tsx
- packages/alouette/src/ui/inputs/CheckboxCardGroup.tsx
- packages/alouette/src/ui/inputs/CheckboxCard.tsx
- packages/alouette/src/ui/inputs/ColorModePicker.tsx
- packages/alouette/src/ui/inputs/ColorModePicker.stories.tsx
---
This skill builds on alouette-theming (token model). Read it first.
# alouette — Inputs
The raw controls. Each one works on its own, controlled (`value` +
`onChangeText` / `onValueChange`) or not; inside a validated form the same
control is rendered from a `FormField`'s `render`, which hands it the field
bindings and the label/error wiring (alouette-forms/SKILL.md).
## Core Patterns
```tsx
import { InputText } from "alouette";
<InputText
mode="email"
value={email}
onChangeText={setEmail}
placeholder="you@example.com"
/>;
```
### Input modes
`mode` bundles the right keyboard, input mode, autocomplete and secure entry:
`"password" | "email" | "number" | "tel" | "url" | "search" | "webSearch"`.
A one-time code (SMS, e-mail, authenticator) is `InputCode`, never a row of
`InputText`s: one input holds the code behind its cells, so paste, OS autofill,
Backspace and the screen reader see a single field. Modes, `onComplete` and the
form wiring: [references/input-code.md](references/input-code.md).
A password is `InputPassword`, not `mode="password"`: that mode plus an eye
toggle in the field (`aria-pressed` while the password shows, named by
`toggleLabel`, default "Show password"), controlled through `visible` /
`defaultVisible` / `onVisibleChange`. Pass `autoComplete="new-password"` on a
sign-up form.
### Slots: a glyph or an icon button in the field
`startSlot` / `endSlot` overlay the field's leading / trailing square (`control-md`), the text
padded past them: an `Icon` carrying its own ink (`text-muted`, or
`text-form-disabled-text` on a disabled field) or a `soft` `sm` `IconButton`.
Fixed-width content only, never a prefix text. With a slot, `className` lands
on the frame around the input, the box the parent lays out.
```tsx
<InputPassword autoComplete="new-password" toggleLabel="Afficher le mot de passe" />
<InputText placeholder="Search" startSlot={<Icon icon={<MagnifyingGlassRegularIcon />} className="text-muted" />} />
<InputText endSlot={<IconButton variant="soft" size="sm" icon={<CalendarBlankRegularIcon />} aria-label="Pick a date" onPress={openPicker} />} />
```
### TextArea, Switch, disabled
```tsx
<TextArea value={notes} onChangeText={setNotes} placeholder="Notes" />
<Switch checked={on} onValueChange={setOn} /> {/* controlled */}
<Switch onValueChange={(v) => log(v)} /> {/* uncontrolled */}
<InputText disabled value={value} />
<Switch disabled checked={on} />
```
### Select, autocomplete and single-select groups
`Select` picks one value from a list without typing; `InputTextAutocomplete` is a
text field backed by a filtered listbox, for narrowing that list by typing. Three
single-select families share one group-owns-the-value API and compose their
children rather than take an options array: `RadioGroup` + `Radio` (circle-dot
list), `RadioButtonGroup` + `RadioButton` (segmented pill bar) and
`RadioCardGroup` + `RadioCard` (icon/label/description cards).
Multi-select: `CheckboxGroup`, `CheckboxCardGroup` (`values: string[]`) and a standalone boolean `Checkbox` for form opt-ins (an immediate setting stays a `Switch`).
`RadioButtonGroup` also takes `variant="icon"` — a pill of square icon-only
chips, each option's `label` staying its accessible name. `ColorModePicker` is
the light/dark control built on it: it reports a `ColorModePreference` and the
app applies it by passing it to a `ScopedTheme` (alouette-theming/SKILL.md).
Props, platform behavior and examples: [references/choice-inputs.md](references/choice-inputs.md).
## Common Mistakes
### MEDIUM Disabling an input with editable={false}
Wrong:
```tsx
<InputText editable={false} />
```
Correct:
```tsx
<InputText disabled />
```
`InputText` exposes a `disabled` prop that sets `editable`, `aria-disabled` and
the disabled styling together; passing `editable` directly skips the disabled
visual state and a11y.
Source: packages/alouette/src/ui/inputs/InputText.tsx
### MEDIUM Setting keyboardType / secureTextEntry by hand
Wrong:
```tsx
<InputText secureTextEntry autoComplete="current-password" />
<InputText keyboardType="email-address" inputMode="email" />
```
Correct:
```tsx
<InputPassword />
<InputText mode="email" />
```
The `mode` prop bundles `inputMode` + `keyboardType` + `autoComplete` +
`secureTextEntry` consistently across platforms; setting them piecemeal is
error-prone. A password also gets its show/hide toggle from `InputPassword`.
Source: packages/alouette/src/ui/inputs/InputText.tsx (MODE_PROPS); ui/inputs/InputPassword.tsx
### MEDIUM Wiring Switch like a web checkbox
Wrong:
```tsx
<Switch value={on} onChange={(e) => setOn(e.target.checked)} />
```
Correct:
```tsx
<Switch checked={on} onValueChange={setOn} />
```
`Switch` is controlled via `checked` and reports through
`onValueChange(value: boolean)`. `value`/`onChange` with `e.target` do nothing
in React Native.
Source: packages/alouette/src/ui/inputs/Switch.tsx
### MEDIUM Picking the wrong single-select family
`RadioGroup` + `Radio`: vertical circle-dot list (longer option lists, labeled
form fields). `RadioButtonGroup` + `RadioButton`: horizontal segmented pill bar
(2–4 compact, equal-weight choices like view mode or time range).
`RadioCardGroup` + `RadioCard`: cards, for a few options that each need an icon
and a line of explanation. None of the three replaces the two components for long
lists: `Select` when the value is picked from the list, `InputTextAutocomplete`
when the user types to narrow it.
The three share one context, so a child must sit inside its own group: a
`RadioCard` under a `RadioGroup` renders, but a `Radio` outside any of the three
throws "Radio, RadioButton and RadioCard must be rendered inside a RadioGroup,
RadioButtonGroup or RadioCardGroup."
Source: packages/alouette/src/ui/inputs/RadioGroup.tsx; ui/inputs/RadioButtonGroup.tsx; ui/inputs/RadioCardGroup.tsx