# List

> Organism — orn-ui

> ⚠️ Requires <UIProvider>: This component (like every orn-ui component) must render inside a <UIProvider> ancestor, or it throws at runtime. See https://orn-ui-docs.vercel.app/getting-started.md

> Runs on Expo SDK 54, 55, 56 and 57, and on bare React Native >=0.81 with react >=19.1. No native modules — works in Expo Go, no prebuild.

## Installation

Install just this component (copies the source into your project, no npm dependency)
```bash
npx orn-ui add list
```

Or install the whole package and import it
```tsx
pnpm add orn-ui
import { List } from 'orn-ui/list';
```

Depends on: core (theme + icons), empty-state, skeleton, spinner

## Variants

### Loaded

```tsx
<List
  data={DATA}
  keyExtractor={(item) => item.id}
  isLoading={false}
  renderItem={({ item }) => (
    <Card style={{ marginBottom: 8 }}>
      <Body>{item.name}</Body>
    </Card>
  )}
/>
```

### Loading

```tsx
<List data={[]} keyExtractor={(i: any) => i.id} isLoading loadingText="Fetching items..." renderItem={() => null} />
```

### Empty

```tsx
<View style={{ flex: 1 }}>
  <Button
    title={showEmpty ? 'Reset' : 'Simulate empty result'}
    variant="outline"
    onPress={() => setShowEmpty((v) => !v)}
    style={{ marginBottom: 12 }}
  />
  <List
    data={showEmpty ? [] : DATA.slice(0, 3)}
    keyExtractor={(item: any) => item.id}
    isLoading={false}
    emptyTitle="No items"
    emptyDescription="Try a different filter"
    renderItem={({ item }: any) => (
      <Card style={{ marginBottom: 8 }}>
        <Body>{item.name}</Body>
      </Card>
    )}
  />
</View>
```

## Full demo source

```tsx
const variants: VariantDef[] = [
  {
    label: 'Loaded',
    content: (
      <List
        data={DATA}
        keyExtractor={(item) => item.id}
        isLoading={false}
        renderItem={({ item }) => (
          <Card style={{ marginBottom: 8 }}>
            <Body>{item.name}</Body>
          </Card>
        )}
      />
    ),
  },
  {
    label: 'Loading',
    content: <List data={[]} keyExtractor={(i: any) => i.id} isLoading loadingText="Fetching items..." renderItem={() => null} />,
  },
  {
    label: 'Empty',
    content: (
      <View style={{ flex: 1 }}>
        <Button
          title={showEmpty ? 'Reset' : 'Simulate empty result'}
          variant="outline"
          onPress={() => setShowEmpty((v) => !v)}
          style={{ marginBottom: 12 }}
        />
        <List
          data={showEmpty ? [] : DATA.slice(0, 3)}
          keyExtractor={(item: any) => item.id}
          isLoading={false}
          emptyTitle="No items"
          emptyDescription="Try a different filter"
          renderItem={({ item }: any) => (
            <Card style={{ marginBottom: 8 }}>
              <Body>{item.name}</Body>
            </Card>
          )}
        />
      </View>
    ),
  },
];
return <VariantList variants={variants} fill />;
```

## Props

| Name | Type | Default | Description |
|---|---|---|---|
| `data` | `T[]` | — | — |
| `keyExtractor` | `(item: T, index: number) => string` | — | — |
| `renderItem` | `ListRenderItem<T>` | — | — |
| `isLoading` | `boolean` | — | Initial load: while true and there's no data, placeholders are shown. |
| `isRefreshing?` | `boolean` | false | Reload with data already on screen (pull-to-refresh). |
| `isLoadingMore?` | `boolean` | false | — |
| `isReady?` | `boolean` | true | Controlled by the consumer: while false, a full-screen spinner is shown. |
| `loadingText?` | `string` | — | — |
| `loadingMoreText?` | `string` | — | — |
| `skeletonCount?` | `number` | 6 | Ghost rows for the initial load. |
| `renderSkeletonItem?` | `() => ReactElement<unknown, string \| JSXElementConstructor<any>>` | — | Custom placeholder, to match the real shape of the item. |
| `onEndReached?` | `() => void` | — | — |
| `onEndReachedThreshold?` | `number` | 0.3 | — |
| `onRefresh?` | `() => void` | — | — |
| `emptyTitle?` | `string` | — | — |
| `emptyDescription?` | `string` | — | — |
| `emptyIconName?` | `IconName` | — | — |
| `ListHeaderComponent?` | `ReactElement<unknown, string \| JSXElementConstructor<any>> \| ComponentType<any>` | — | — |
| `ListFooterComponent?` | `ReactElement<unknown, string \| JSXElementConstructor<any>> \| ComponentType<any>` | — | — |
| `contentContainerStyle?` | `ViewStyle` | — | — |
| `containerStyle?` | `ViewStyle` | — | — |
| `ListComponent?` | `ComponentType<any>` | FlatList | List component to use (FlashList, etc). |
| `listProps?` | `Record<string, unknown>` | — | — |
