# ListItem & List (React Native)

> Rows for settings, contacts and inboxes: leading icon, title and description, trailing value, control or chevron.

GramproKit for React Native · Mobile · Beta · Source: https://kit.gramproindia.com/native/docs/list-item

> **Beta:** React Native support is in beta. APIs may change or break between prereleases (npm tag `native`).

_Interactive demo:_ [open the live example](https://kit.gramproindia.com/native/docs/list-item). The example's source:

```tsx
import { useState } from "react";
import { Text, View } from "react-native";
import { Avatar } from "@/component-lib/avatar";
import { Badge } from "@/component-lib/badge";
import { useKitTheme } from "@/component-lib/shared/native";
import { Switch } from "@/component-lib/switch";
import { List, ListItem, ListSection } from "@/component-lib/list-item";
import { Section } from "./layout"; // Section and Row: page layout for the demo

/** A coloured rounded square with a letter: a settings-style icon without SVG. */
function Tile({ color, letter }: { color: string; letter: string }) {
  return (
    <View style={{ width: 28, height: 28, borderRadius: 7, backgroundColor: color, alignItems: "center", justifyContent: "center" }}>
      <Text style={{ color: "#fff", fontWeight: "800", fontSize: 13 }}>{letter}</Text>
    </View>
  );
}

export function ListItemDemo() {
  const { tokens } = useKitTheme();
  const [push, setPush] = useState(true);
  const [taps, setTaps] = useState(0);
  return (
    <>
      <Section title="ListSection · inset (settings)">
        <ListSection header="Account" footer={`Opened ${taps} time${taps === 1 ? "" : "s"}. Rows with a chevron open a screen.`}>
          <ListItem leading={<Tile color="#2563eb" letter="L" />} title="Language" value="English" chevron onPress={() => setTaps((n) => n + 1)} />
          <ListItem
            leading={<Tile color="#15803d" letter="N" />}
            title="Push notifications"
            trailing={<Switch aria-label="Push notifications" checked={push} onCheckedChange={setPush} />}
          />
          <ListItem leading={<Tile color="#b45309" letter="₹" />} title="Currency" value="INR (₹)" chevron onPress={() => setTaps((n) => n + 1)} />
          <ListItem title="Sign out" destructive onPress={() => setTaps((n) => n + 1)} />
        </ListSection>
      </Section>
      <Section title="List · plain (inbox)">
        <List style={{ marginHorizontal: -16 }}>
          <ListItem
            leading={<Avatar name="Anand Remanan" size="md" />}
            title="Anand Remanan"
            description="Invoice INV-2041 is ready for review. The totals changed after the GST update."
            trailing={<Badge variant="accent">New</Badge>}
            onPress={() => setTaps((n) => n + 1)}
          />
          <ListItem
            leading={<Avatar name="Gita Hari" size="md" />}
            title="Gita Hari"
            description="Shared the Q3 ledger with you."
            value="09:41"
            onPress={() => setTaps((n) => n + 1)}
          />
          <ListItem leading={<Avatar name="Old Account" size="md" />} title="Old account" description="Archived" disabled />
        </List>
        <Text style={{ color: tokens.muted, fontSize: tokens.fontSize - 2 }}>Long descriptions stop at two lines.</Text>
      </Section>
    </>
  );
}
```

## Install

```bash
npx @grampro/kit@native add ListItem
```

## Usage

```tsx
import { ListItem, ListSection } from "@/component-lib/list-item";

<ListSection header="Account" footer="Signed in as anand@example.com">
  <ListItem title="Language" value="English" chevron onPress={openLanguage} />
  <ListItem title="Notifications" trailing={<Switch checked={on} onCheckedChange={setOn} />} />
  <ListItem title="Sign out" destructive onPress={signOut} />
</ListSection>
```

## Props

### ListItemProps

| Prop | Type | Description |
|---|---|---|
| `leading` | `ReactNode` | Icon or avatar before the text. |
| `title` (required) | `ReactNode` |   |
| `description` | `ReactNode` | Supporting text under the title. |
| `numberOfLines` | `number` | Lines of description before truncating. Default 2. |
| `value` | `ReactNode` | Settings-style value text at the end, e.g. "English". |
| `trailing` | `ReactNode` | Anything at the end: a Switch, a Badge, a button. |
| `chevron` | `boolean` | A disclosure chevron at the end: the row opens something. |
| `destructive` | `boolean` | Red text for delete / sign out rows. |
| `disabled` | `boolean` |   |
| `onPress` | `(event: GestureResponderEvent) => void` |   |
| `onLongPress` | `(event: GestureResponderEvent) => void` |   |
| `style` | `StyleProp<ViewStyle> \| ((state: { pressed: boolean }) => StyleProp<ViewStyle>)` |   |
| `styles` | `Partial<{ leading: StyleProp<ViewStyle>; title: StyleProp<TextStyle>; description: Styl…` |   |

### ListProps

| Prop | Type | Description |
|---|---|---|
| `variant` | `ListVariant` | `plain`: full-width rows. `inset`: a rounded card of rows (iOS settings). Default `plain`. |
| `divided` | `boolean` | Hairlines between rows, inset past the leading slot. Default true. |
| `style` | `StyleProp<ViewStyle>` |   |
| `children` | `ReactNode` |   |

### ListSectionProps

| Prop | Type | Description |
|---|---|---|
| `header` | `ReactNode` | Small caps label above the group. |
| `footer` | `ReactNode` | Explanatory text below the group. |
| `variant` | `ListVariant` |   |
| `divided` | `boolean` |   |
| `style` | `StyleProp<ViewStyle>` |   |
| `children` | `ReactNode` |   |

## Notes

- Rows are at least 44dp tall (56dp with a description).
- A pressable row with a chevron is announced as a link, otherwise as a button.
- `ListSection` defaults to the rounded `inset` look of iOS settings.
- Mobile only: there is no web version of this component.
