component. -->
Table Primitive
Demo
Shows a table component.
npx @react-native-reusables/cli@latest add table
Copy/paste the following code to ~/components/ui/table.tsx
~/components/ui/table.tsx
import * as TablePrimitive from '@rn-primitives/table';import * as React from 'react';import { cn } from '~/lib/utils';import { TextClassContext } from '~/components/ui/text'; const Table = React.forwardRef<TablePrimitive.RootRef, TablePrimitive.RootProps>( ({ className, ...props }, ref) => ( <TablePrimitive.Root ref={ref} className={cn('w-full caption-bottom text-sm', className)} {...props} /> ));Table.displayName = 'Table'; const TableHeader = React.forwardRef<TablePrimitive.HeaderRef, TablePrimitive.HeaderProps>( ({ className, ...props }, ref) => ( <TablePrimitive.Header ref={ref} className={cn('border-border [&_tr]:border-b', className)} {...props} /> ));TableHeader.displayName = 'TableHeader'; const TableBody = React.forwardRef<TablePrimitive.BodyRef, TablePrimitive.BodyProps>( ({ className, style, ...props }, ref) => ( <TablePrimitive.Body ref={ref} className={cn('flex-1 border-border [&_tr:last-child]:border-0', className)} style={[{ minHeight: 2 }, style]} {...props} /> ));TableBody.displayName = 'TableBody'; const TableFooter = React.forwardRef<TablePrimitive.FooterRef, TablePrimitive.FooterProps>( ({ className, ...props }, ref) => ( <TablePrimitive.Footer ref={ref} className={cn('bg-muted/50 font-medium [&>tr]:last:border-b-0', className)} {...props} /> ));TableFooter.displayName = 'TableFooter'; const TableRow = React.forwardRef<TablePrimitive.RowRef, TablePrimitive.RowProps>( ({ className, ...props }, ref) => ( <TablePrimitive.Row ref={ref} className={cn( 'flex-row border-border border-b web:transition-colors web:hover:bg-muted/50 web:data-[state=selected]:bg-muted', className )} {...props} /> ));TableRow.displayName = 'TableRow'; const TableHead = React.forwardRef<TablePrimitive.HeadRef, TablePrimitive.HeadProps>( ({ className, ...props }, ref) => ( <TextClassContext.Provider value='text-muted-foreground'> <TablePrimitive.Head ref={ref} className={cn( 'h-12 px-4 text-left justify-center font-medium [&:has([role=checkbox])]:pr-0', className )} {...props} /> </TextClassContext.Provider> ));TableHead.displayName = 'TableHead'; const TableCell = React.forwardRef<TablePrimitive.CellRef, TablePrimitive.CellProps>( ({ className, ...props }, ref) => ( <TablePrimitive.Cell ref={ref} className={cn('p-4 align-middle [&:has([role=checkbox])]:pr-0', className)} {...props} /> ));TableCell.displayName = 'TableCell'; export { Table, TableBody, TableCell, TableFooter, TableHead, TableHeader, TableRow };
import { FlashList } from '@shopify/flash-list';import { Stack } from 'expo-router';import * as React from 'react';import { Alert, ScrollView, View, useWindowDimensions } from 'react-native';import { useSafeAreaInsets } from 'react-native-safe-area-context';import { Button } from '~/components/ui/button';import { Table, TableBody, TableCell, TableFooter, TableHead, TableHeader, TableRow,} from '~/components/ui/table';import { Text } from '~/components/ui/text';import { ChevronDown } from '~/lib/icons/ChevronDown';import { cn } from '~/lib/utils'; const INVOICES = [ { invoice: 'INV001', paymentStatus: 'Paid', totalAmount: '$250.00', paymentMethod: 'Credit Card', }, ...]; const MIN_COLUMN_WIDTHS = [120, 120, 100, 120]; function Example() { const { width } = useWindowDimensions(); const insets = useSafeAreaInsets(); const columnWidths = React.useMemo(() => { return MIN_COLUMN_WIDTHS.map((minWidth) => { const evenWidth = width / MIN_COLUMN_WIDTHS.length; return evenWidth > minWidth ? evenWidth : minWidth; }); }, [width]); return ( <ScrollView horizontal bounces={false} showsHorizontalScrollIndicator={false}> <Table aria-labelledby='invoice-table'> <TableHeader> <TableRow> <TableHead className='px-0.5' style={{ width: columnWidths[0] }}> <Text>Invoice</Text> </TableHead> <TableHead style={{ width: columnWidths[1] }}> <Text>Status</Text> </TableHead> <TableHead style={{ width: columnWidths[2] }}> <Text>Method</Text> </TableHead> <TableHead style={{ width: columnWidths[3] }}> <Text className='text-center md:text-right md:pr-5'>Amount</Text> </TableHead> </TableRow> </TableHeader> <TableBody> <FlashList data={INVOICES} estimatedItemSize={45} contentContainerStyle={{ paddingBottom: insets.bottom, }} showsVerticalScrollIndicator={false} renderItem={({ item: invoice, index }) => { return ( <TableRow key={invoice.invoice} className={cn('active:bg-secondary', index % 2 && 'bg-muted/40 ')} > <TableCell style={{ width: columnWidths[0] }}> <Text>{invoice.invoice}</Text> </TableCell> <TableCell style={{ width: columnWidths[1] }}> <Text>{invoice.paymentStatus}</Text> </TableCell> <TableCell style={{ width: columnWidths[2] }}> <Text>{invoice.paymentMethod}</Text> </TableCell> <TableCell style={{ width: columnWidths[3] }} className='items-end '> <Button variant='secondary' size='sm' className='shadow-sm shadow-foreground/10 mr-3' onPress={() => { Alert.alert( invoice.totalAmount, `You pressed the price button on invoice ${invoice.invoice}.` ); }} > <Text>{invoice.totalAmount}</Text> </Button> </TableCell> </TableRow> ); }} ListFooterComponent={() => { return ( <> <TableFooter> <TableRow> <TableCell className='flex-1 justify-center'> <Text className='text-foreground'>Total</Text> </TableCell> <TableCell className='items-end pr-8'> <Button size='sm' variant='ghost' onPress={() => { Alert.alert( 'Total Amount', `You pressed the total amount price button.` ); }} > <Text>$2,500.00</Text> </Button> </TableCell> </TableRow> </TableFooter> <View className='items-center py-3 ios:pb-0'> <Text nativeID='invoice-table' className='items-center text-sm text-muted-foreground' > A list of your recent invoices. </Text> </View> </> ); }} /> </TableBody> </Table> </ScrollView> );}
Extends View props
View