suiss/uim · Pattern

Table List

Turns table-style rows and columns into a grouped list of rows with a title, description and trailing values.

Table List is an open-source mobile pattern from suiss/uim: components composed into a flow for React Native and Expo, with SwiftUI and Jetpack Compose versions built from the same design tokens. The @esuiss/uim CLI copies its source into your project, so you own the code.

iOS
Table List on iOS in light mode

TableList takes rows and a columns definition, and renders each row as a TableListRow inside one rounded group. Each column has a slot that decides where its cell goes: the row title, the description line, the trailing side, or nowhere.

The row parts are also exported, so you can build the same grouped look inside a FlatList for long or virtualized lists.

Installation

$ pnpm dlx @esuiss/uim@latest add table-list

The CLI also adds what it builds on: Item, Text.

Manual

  1. Install the dependencies:
npx expo install cn
  1. Add the pieces it builds on: Item, Text.

  2. Copy the source into components/patterns/table-list.tsx:

uniwind/components/patterns/table-list.tsx
import { cn } from "cn"
import * as React from "react"
import { View, type ViewProps } from "react-native"
import {
  Item,
  ItemActions,
  ItemContent,
  ItemDescription,
  ItemTitle,
} from "@/components/ui/item"
import { Text } from "@/components/ui/text"

type TableListColumn<T> = {
  key: string
  header: React.ReactNode
  cell: (row: T) => React.ReactNode
  1. Update the import paths to match your project.

Usage

import { TableListTitle, TableListHeader, TableListFooter, TableListSeparator, TableListRow, TableList } from "@/components/patterns/table-list"
<View className="gap-8">
  <TableList
    title="Invoices"
    rows={invoices}
    columns={columns}
    getKey={(row) => row.id}
    onRowPress={() => {}}
  />
  <TableList rows={[]} columns={columns} emptyText="No invoices yet." />
</View>

Define columns with key, header, cell and slot. Several description columns are joined with ·, and several trailing columns are shown side by side. Use mobileCell to render a different value than cell in the list, such as a shorter date.

Pass onRowPress to make rows pressable. When there are no rows, emptyText is shown in the group. The TableListColumn type is exported.

With a FlatList, use TableListRow as the item, pass first and last to round the ends, TableListSeparator as ItemSeparatorComponent, and TableListHeader and TableListFooter around the list.

Examples

With flat list

Builds the grouped list in a FlatList with a header, footer and separators.

iOS
Table List (with flat list) on iOS in light mode

API Reference

TableListTitle

A large heading above the list.

ExtendsReact.ComponentProps<typeof Text>

TableListHeader

A small uppercase heading above a group.

ExtendsReact.ComponentProps<typeof Text>

TableListFooter

A note below a group.

ExtendsReact.ComponentProps<typeof Text>

TableListSeparator

An inset divider between rows.

ExtendsViewProps

TableListRow

One row with a title, description and trailing content.

ExtendsReact.ComponentProps<typeof Item>
PropType
About
The row's main text.
Type
React.ReactNode
Default
—
About
A single-line secondary text.
Type
React.ReactNode
Default
—
About
Content on the end side; text is shown in secondary color with tabular numbers.
Type
React.ReactNode
Default
—
About
Rounds the top corners.
Type
boolean
Default
false
About
Rounds the bottom corners.
Type
boolean
Default
false
Type
React.ReactNode
Default
—

TableList

Renders rows from a column definition, with an optional title and empty state.

ExtendsViewProps
PropType
About
The data to render.
Type
T[]
Default
required
About
Column definitions with key, header, cell, optional mobileCell, slot and align.
Type
TableListColumn<T>[]
Default
required
About
Returns a unique key for a row. Defaults to the index.
Type
(row: T, index: number) => React.Key
Default
(_, index) => index
About
Heading shown above the list.
Type
React.ReactNode
Default
—
About
Content shown when rows is empty. Defaults to No results..
Type
React.ReactNode
Default
"No results."
About
Called with the row and index when a row is pressed.
Type
(row: T, index: number) => void
Default
—

Accessibility

  • The group has the list role; rows have the listitem role, or button when onRowPress is set.
  • TableListTitle and TableListHeader have the heading role.
  • Separators are hidden from screen readers.

Notes

  • Rows use bg-surface-secondary and bg-surface-tertiary when pressed.
  • The header and align column fields are not rendered by the list layout.