> ## Documentation Index
> Fetch the complete documentation index at: https://docs.cskn.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# Grouped lists and forms

> Settings-style grouped sections, rows, inline fields, steppers, pickers, date inputs and an edit mode.

Grouped lists are the inset, rounded sections of a system settings screen. Use them for settings, detail screens and forms. They follow the platform: iOS grouped tables, Material lists on Android, macOS System Settings groups and Windows Settings cards on desktop. They work inside and outside a `StackNavigator`.

```tsx theme={null}
import { GroupedSection, GroupedRow, Switch, Icon } from '@cskn/ui';

<GroupedSection header="Notifications" footer="We'll never email you more than once a day.">
  <GroupedRow asLabel title="Daily summary" trailing={<Switch checked={daily} onChange={setDaily} />} />
  <GroupedRow leading={<Icon name="bell" />} title="Sounds" trailing="Chime" chevron onPress={openSounds} />
</GroupedSection>

<GroupedSection>
  <GroupedRow title="Delete account" tone="destructive" centered onPress={confirmDelete} />
</GroupedSection>
```

## GroupedSection

**header** `ReactNode`

Caption above the group: small grey capitals on iOS, accent-colored on Android.

**footer** `ReactNode`

Note under the group.

**separatorInset** `number` (default: 16)

Where the hairline between rows starts, in px. Line it up with the row text, for example 72 with avatars.

## GroupedRow

**title / subtitle** `ReactNode`

Row text.

**leading** `ReactNode`

Icon, thumbnail or emoji tile.

**trailing** `ReactNode`

A value, switch or control at the end.

**chevron** `boolean`

A disclosure chevron: this row opens another screen.

**onPress** `() =\> void`

Makes the row a button that highlights on press.

**asLabel** `boolean`

Render as a `<label>`, so the whole row toggles its `Switch` or checkbox.

**accessory** `ReactNode`

A separate control at the end, outside the row's tap area, for example an "open link" button on a row that otherwise opens an editor.

**tone** `'default' | 'accent' | 'destructive'`

Text color for action rows.

**centered** `boolean`

Center the content, for a lone action row such as "Delete".

**selected** `boolean`

The row whose detail shows beside it in two-column mode.

**disabled** `boolean`

Inactive row.

Put a field directly in a row as its `children` to make it fill the row.

## Fields and controls

| Component | What it is |
| - | - |
| `GroupedInput` | A borderless text field that fills the row. Takes every `<input>` attribute and forwards its ref. |
| `GroupedTextarea` | A borderless text area that grows as you type. |
| `GroupedSelect` | A borderless `<select>` that opens the platform's wheel or dialog. Use it for long option lists. |
| `GroupedPicker` | An inline menu picker in the trailing slot: the value with ⌃⌄ on iOS, a Material dropdown on Android. For short option lists. |
| `GroupedStepper` | − / + in the trailing slot. Holding repeats, speeding up. |
| `GroupedSlider` | A slider that fills the row, with optional icons at each end. |
| `GroupedDateInput` | A date or time in the trailing slot, opening the platform's picker. |

```tsx theme={null}
<GroupedSection header="Reminder">
  <GroupedRow>
    <GroupedInput placeholder="Title" value={title} onChange={(e) => setTitle(e.target.value)} />
  </GroupedRow>
  <GroupedRow title="Repeat" trailing={
    <GroupedPicker aria-label="Repeat" value={repeat} onChange={setRepeat}
      options={[{ value: 'never', label: 'Never' }, { value: 'daily', label: 'Daily' }]} />
  } />
  <GroupedRow title="Snooze" trailing={
    <GroupedStepper value={snooze} onChange={setSnooze} min={5} max={60} step={5}
      format={(v) => `${v} min`} decrementLabel="Less" incrementLabel="More" />
  } />
  <GroupedRow>
    <GroupedSlider aria-label="Volume" value={volume} onChange={setVolume}
      leading={<Icon name="volume-off" size={14} />} trailing={<Icon name="volume" />} />
  </GroupedRow>
</GroupedSection>
```

**GroupedPicker**: `value`, `options` (`{ value, label }[]`), `onChange`, `aria-label` (required), `disabled?`, `style?`.

**GroupedStepper**: `value`, `onChange`, `min?`, `max?`, `step?` (default 1), `decrementLabel` and `incrementLabel` (required accessible names), `showValue?` (default `true`), `format?`.

**GroupedSlider**: `value`, `onChange`, `min?` (default 0), `max?` (default 1), `step?` (default 0.01), `leading?`, `trailing?`, `aria-label` (required), `disabled?`.

## GroupedForm

Wrap form sections in `GroupedForm` and the keyboard's return key moves between fields: every field but the last gets "Next", and the last gets "Done" (which closes the keyboard) or, with `onDone`, "Go" (which runs it). Multi-line fields keep Enter for new lines, and a field with its own `enterKeyHint` keeps it.

```tsx theme={null}
import { GroupedForm, GroupedSection, GroupedRow, GroupedInput, GroupedDateInput } from '@cskn/ui';

<GroupedForm onDone={save}>
  <GroupedSection>
    <GroupedRow><GroupedInput placeholder="Title" value={title} onChange={(e) => setTitle(e.target.value)} /></GroupedRow>
    <GroupedRow><GroupedInput placeholder="Place" value={place} onChange={(e) => setPlace(e.target.value)} /></GroupedRow>
  </GroupedSection>
  <GroupedSection header="When">
    <GroupedRow title="Day" trailing={<GroupedDateInput value={day} onChange={setDay} placeholder="Pick a day" />} />
    <GroupedRow title="Time" trailing={<GroupedDateInput mode="time" value={time} onChange={setTime} />} />
  </GroupedSection>
</GroupedForm>
```

`GroupedForm` takes every `<form>` attribute except `onSubmit`.

## GroupedDateInput

Shows the value formatted for the reader's language (a grey pill on iOS, plain text on Android) and opens the platform's picker on tap. The value stays a plain string.

**value** `string` *required*

`YYYY-MM-DD`, `HH:mm` or `YYYY-MM-DDTHH:mm`, matching `mode`. Empty for none.

**onChange** `(value: string) =\> void` *required*

Receives the new value in the same format.

**mode** `'date' | 'time' | 'datetime'` (default: 'date')

What to pick.

**placeholder** `string`

Shown while empty.

**min / max** `string`

Limits, same format.

**native** `boolean`

Use the shell's [system picker](https://docs.cskn.dev/sdk/native/system-pickers.md#date-picker) (the iOS calendar sheet, Material dialogs). Defaults to `UIProvider`'s `systemDialogs`. Without a shell it falls back to the browser's picker.

**locale** `string`

Language for formatting. Defaults to the shell's, then the page's, then the browser's.

**doneLabel / cancelLabel** `string`

Buttons of the system picker.

## EditableList

An edit mode for a grouped list, like Reminders or a settings list. While `editing`, each row gets a delete control and a drag handle, and the rows themselves stop responding to taps.

```tsx theme={null}
import { EditableList, GroupedSection, GroupedRow, Button } from '@cskn/ui';

<GroupedSection header={<>Shelf <Button size="sm" variant="ghost" onClick={() => setEditing((e) => !e)}>{editing ? 'Done' : 'Edit'}</Button></>}>
  <EditableList
    items={books}
    keyOf={(b) => b.id}
    editing={editing}
    deleteLabel="Delete"
    onDelete={remove}
    onReorder={setBooks}
    renderRow={(b) => <GroupedRow title={b.title} chevron onPress={() => open(b)} />}
  />
</GroupedSection>
```

**items** `T[]` *required*

The rows' data.

**keyOf** `(item) =\> string` *required*

A stable key per item.

**renderRow** `(item) =\> ReactNode` *required*

A row as it looks outside edit mode, usually a `GroupedRow`, maybe in a `SwipeRow`.

**editing** `boolean` *required*

Edit mode on or off.

**deleteLabel** `string` *required*

iOS's confirming Delete button, and the delete control's accessible name.

**onDelete** `(item) =\> void`

Gives each row a delete control. On iOS the red ⊖ turns and a Delete button slides in, which deletes. On Android the control deletes at once, so pair it with an [undo toast](https://docs.cskn.dev/ui/components/feedback.md#undo-instead-of-confirm).

**onReorder** `(items: T[]) =\> void`

Gives each row a drag handle; called with the new order on drop. The list scrolls by itself near the edges, and ↑ / ↓ move a focused handle by one place.

**reorderLabel** `string` (default: 'Reorder')

Accessible name of a drag handle.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.