orn-ui
Organism

List

Requires <UIProvider> — Getting Started →

Installation

Install just this component (copies the source into your project, no npm dependency)

npx orn-ui add list

Or install the whole package and import it

pnpm add orn-ui
import { List } from 'orn-ui/list';
Depends on:core (theme + icons)empty-stateskeletonspinner

Usage

  • when to use — Any data list: it bundles loading, empty and pagination so each screen does not reinvent them.
  • isLoading / isReady — `isLoading` is the data fetch; `isReady` is everything the screen needs before rendering at all.
  • emptyTitle / emptyDescription — Feed the EmptyState it renders when there is nothing to show.
  • onEndReached / isLoadingMore — Pagination: the callback loads, the flag shows the footer spinner.
  • ListComponent — `FlatList` by default; swap in FlashList without touching the rest.
Demo clip not recorded yet — see MEDIA.md

Variants

Loaded

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

Loading

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

Empty

<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
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

NameTypeDefaultDescription
dataT[]
keyExtractor(item: T, index: number) => string
renderItemListRenderItem<T>
isLoadingbooleanInitial load: while true and there's no data, placeholders are shown.
isRefreshing?booleanfalseReload with data already on screen (pull-to-refresh).
isLoadingMore?booleanfalse
isReady?booleantrueControlled by the consumer: while false, a full-screen spinner is shown.
loadingText?string
loadingMoreText?string
skeletonCount?number6Ghost rows for the initial load.
renderSkeletonItem?() => ReactElement<unknown, string | JSXElementConstructor<any>>Custom placeholder, to match the real shape of the item.
onEndReached?() => void
onEndReachedThreshold?number0.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>FlatListList component to use (FlashList, etc).
listProps?Record<string, unknown>