# SearchList

> 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 search-list
```

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

Depends on: core (theme + icons), input, empty-state, skeleton, spinner, icon-button, pressable-scale

## Variants

### Search + results

```tsx
<SearchList
  searchValue={query}
  onSearchChange={setQuery}
  data={data.map((name) => ({ name }))}
  keyExtractor={(item) => item.name}
  renderItem={({ item }) => (
    <Card style={{ marginBottom: 8 }}>
      <Body>{item.name}</Body>
    </Card>
  )}
  emptyTitle="No matches"
/>
```

### With scan action

```tsx
<SearchList
  searchValue=""
  onSearchChange={() => {}}
  onScanPress={() => {}}
  data={[]}
  keyExtractor={(item: any) => item.name}
  renderItem={() => null}
  emptyTitle="Scan a barcode or search"
/>
```

## Full demo source

```tsx
const variants: VariantDef[] = [
  {
    label: 'Search + results',
    content: (
      <SearchList
        searchValue={query}
        onSearchChange={setQuery}
        data={data.map((name) => ({ name }))}
        keyExtractor={(item) => item.name}
        renderItem={({ item }) => (
          <Card style={{ marginBottom: 8 }}>
            <Body>{item.name}</Body>
          </Card>
        )}
        emptyTitle="No matches"
      />
    ),
  },
  {
    label: 'With scan action',
    content: (
      <SearchList
        searchValue=""
        onSearchChange={() => {}}
        onScanPress={() => {}}
        data={[]}
        keyExtractor={(item: any) => item.name}
        renderItem={() => null}
        emptyTitle="Scan a barcode or search"
      />
    ),
  },
];
return <VariantList variants={variants} fill />;
```

## Props

| Name | Type | Default | Description |
|---|---|---|---|
| `header?` | `ReactNode` | — | Optional chrome above the search field (e.g. back button + title). |
| `searchValue` | `string` | — | — |
| `onSearchChange` | `(text: string) => void` | — | — |
| `searchPlaceholder?` | `string` | — | — |
| `searchIsLoading?` | `boolean` | false | — |
| `onScanPress?` | `() => void` | — | — |
| `scanAccessibilityLabel?` | `string` | Scan | — |
| `extraActions?` | `ReactNode` | — | — |
| `data` | `T[]` | — | — |
| `keyExtractor` | `(item: T, index: number) => string` | — | — |
| `renderItem` | `ListRenderItem<T>` | — | — |
| `isLoading?` | `boolean` | false | Initial load: while true and there's no data, placeholders are shown. |
| `loadingMode?` | `'replace' \| 'overlay'` | replace | 'replace' swaps the whole list for a spinner; 'overlay' shows it on top, keeping the layout. |
| `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 fullscreen spinner is shown. |
| `loadingText?` | `string` | — | — |
| `loadingMoreText?` | `string` | — | — |
| `hasMore?` | `boolean` | false | — |
| `noMoreText?` | `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. |
| `onLoadMore?` | `() => void` | — | — |
| `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?` | `StyleProp<ViewStyle>` | — | — |
| `containerStyle?` | `ViewStyle` | — | — |
| `ListComponent?` | `ComponentType<any>` | FlatList | List component to use (FlashList, etc). |
| `listProps?` | `Record<string, unknown>` | — | — |
