AniUI

Table

A compound table component with header, body, rows, and cells for displaying structured data.

FeatureFreePro
Priority supportNoYes
Projects3Unlimited
Team members1Unlimited
Web preview — components render natively on iOS & Android
<Table>
  <TableHeader>
    <TableRow>
      <TableHead>Name</TableHead>
      <TableHead>Status</TableHead>
      <TableHead>Role</TableHead>
    </TableRow>
  </TableHeader>
  <TableBody>
    <TableRow>
      <TableCell>Alice</TableCell>
      <TableCell>Active</TableCell>
      <TableCell>Admin</TableCell>
    </TableRow>
    <TableRow>
      <TableCell>Bob</TableCell>
      <TableCell>Inactive</TableCell>
      <TableCell>User</TableCell>
    </TableRow>
    <TableRow>
      <TableCell>Charlie</TableCell>
      <TableCell>Active</TableCell>
      <TableCell>Editor</TableCell>
    </TableRow>
  </TableBody>
</Table>

Installation#

npx @aniui/cli add table

Usage#

app/index.tsx
import {
  Table,
  TableHeader,
  TableBody,
  TableRow,
  TableHead,
  TableCell,
} from "@/components/ui/table";

export function MyScreen() {
  return (
    <Table>
      <TableHeader>
        <TableRow>
          <TableHead>Name</TableHead>
          <TableHead>Status</TableHead>
          <TableHead>Role</TableHead>
        </TableRow>
      </TableHeader>
      <TableBody>
        <TableRow>
          <TableCell>Alice</TableCell>
          <TableCell>Active</TableCell>
          <TableCell>Admin</TableCell>
        </TableRow>
        <TableRow>
          <TableCell>Bob</TableCell>
          <TableCell>Inactive</TableCell>
          <TableCell>User</TableCell>
        </TableRow>
      </TableBody>
    </Table>
  );
}

Examples#

Default#

FeatureFreePro
Priority supportNoYes
Projects3Unlimited
Team members1Unlimited
Web preview — components render natively on iOS & Android
<Table>
  <TableHeader>
    <TableRow>
      <TableHead>Name</TableHead>
      <TableHead>Status</TableHead>
      <TableHead>Role</TableHead>
    </TableRow>
  </TableHeader>
  <TableBody>
    <TableRow>
      <TableCell>Alice</TableCell>
      <TableCell>Active</TableCell>
      <TableCell>Admin</TableCell>
    </TableRow>
    <TableRow>
      <TableCell>Bob</TableCell>
      <TableCell>Inactive</TableCell>
      <TableCell>User</TableCell>
    </TableRow>
    <TableRow>
      <TableCell>Charlie</TableCell>
      <TableCell>Active</TableCell>
      <TableCell>Editor</TableCell>
    </TableRow>
  </TableBody>
</Table>

Props#

Table#

PropTypeDefault
className
string
children
ReactNode

Also accepts all ScrollView props from React Native.

TableHeader / TableBody / TableRow#

PropTypeDefault
className
string
children
ReactNode

Also accepts all View props from React Native.

TableHead / TableCell#

PropTypeDefault
className
string
children
ReactNode

Also accepts all Text props from React Native.

Accessibility#

  • Data table with semantic row/cell structure.
  • Header cells are distinguished from body cells for screen readers.

Source#

components/ui/table.tsx
import React, { createContext, useContext } from "react";
import { View, Text, ScrollView, type StyleProp, type ViewStyle } from "react-native";
import { cn } from "@/lib/utils";

type TableContextValue = { truncate: boolean; defaultColumnWidth: number };
const TableContext = createContext<TableContextValue>({ truncate: false, defaultColumnWidth: 150 });

export type TableViewProps = React.ComponentPropsWithoutRef<typeof View> & { className?: string; children?: React.ReactNode };
export interface TableProps extends React.ComponentPropsWithoutRef<typeof ScrollView> {
  className?: string;
  children?: React.ReactNode;
  /** When true, fit columns to container width and truncate long content. Default false: each cell
   *  has a fixed pixel width and the table scrolls horizontally if total content exceeds the viewport. */
  truncate?: boolean;
  /** Default pixel width for each cell. Used in scroll mode (truncate=false). Defaults to 150. */
  defaultColumnWidth?: number;
}
export interface TableCellProps extends TableViewProps { textClassName?: string }

const truncateCellStyle: StyleProp<ViewStyle> = { flexGrow: 1, flexShrink: 1, flexBasis: 0, minWidth: 0, overflow: "hidden" };

export function Table({ className, children, truncate = false, defaultColumnWidth = 150, ...props }: TableProps) {
  return (
    <TableContext.Provider value={{ truncate, defaultColumnWidth }}>
      <ScrollView horizontal scrollEnabled={!truncate} className={cn("rounded-md border border-border", className)} {...props}>
        <View className="min-w-full">{children}</View>
      </ScrollView>
    </TableContext.Provider>
  );
}

export function TableHeader({ className, ...props }: TableViewProps) {
  return <View className={cn("bg-muted/50", className)} {...props} />;
}

export function TableBody({ className, ...props }: TableViewProps) {
  return <View className={className} {...props} />;
}

export function TableRow({ className, ...props }: TableViewProps) {
  return <View className={cn("flex-row border-b border-border", className)} {...props} />;
}

export function TableHead({ className, textClassName, children, style, ...props }: TableCellProps) {
  const { truncate, defaultColumnWidth } = useContext(TableContext);
  const isText = typeof children === "string" || typeof children === "number";
  const widthStyle: StyleProp<ViewStyle> = truncate ? truncateCellStyle : { width: defaultColumnWidth, overflow: "hidden" };
  return (
    <View style={[widthStyle, style]} className={cn("justify-center px-4 py-3", className)} {...props}>
      {isText ? <Text className={cn("text-sm font-medium text-muted-foreground", textClassName)} numberOfLines={1}>{children}</Text> : children}
    </View>
  );
}

export function TableCell({ className, textClassName, children, style, ...props }: TableCellProps) {
  const { truncate, defaultColumnWidth } = useContext(TableContext);
  const isText = typeof children === "string" || typeof children === "number";
  const widthStyle: StyleProp<ViewStyle> = truncate ? truncateCellStyle : { width: defaultColumnWidth, overflow: "hidden" };
  return (
    <View style={[widthStyle, style]} className={cn("justify-center px-4 py-3", className)} {...props}>
      {isText ? <Text className={cn("text-sm text-foreground", textClassName)} numberOfLines={1}>{children}</Text> : children}
    </View>
  );
}