Table
Semantic data-table primitives that render real table/th scope/aria-sort semantics on Web.
Identity
Section titled “Identity”- Category: Data display
- Status: stable public Registry/export-map component family
- Targets: iOS · Android · Web, subject to the compatibility contract
- Source:
packages/ui/src/components/table.tsx
Import
Section titled “Import”import { Table, TableBody, TableCaption, TableCell, TableFooter, TableHead, TableHeader, TableRow } from '@beemvp/beeui-ui';There is no documented deep/private source import. For source ownership from a BeeUI checkout:
pnpm beeui -- add tableRegistry metadata: registry/registry.json.
Composition and public API
Section titled “Composition and public API”- Family exports:
TableTableBodyTableCaptionTableCellTableFooterTableHeadTableHeaderTableRow
Exported types: TableBodyProps, TableCaptionProps, TableCellProps, TableFooterProps, TableHeaderProps, TableHeadProps, TableLayout, TableProps, TableRowProps, TableSortDirection
The generated API inventory is mechanically joined to packages/ui/src/index.ts, Registry metadata, and the component reference contract. For behavior details and defaults, use the canonical component behavior catalog rather than copying TypeScript declarations into a second hand-maintained table.
State and behavior contract
Section titled “State and behavior contract”Controlled/uncontrolled props, callbacks, disabled semantics, normalization/fail-safe behavior, and mount/unmount rules are defined by the public types and the canonical behavior catalog. The executable fixtures below are the source-grounded usage examples; consumers should not infer state ownership from DOM structure or another UI library.
Provider and dependencies
Section titled “Provider and dependencies”- No additional provider is required by this family.
BeeUIProviderremains the recommended application root. - Peer/native dependencies visible to this Registry item:
react,react-native - Registry dependency closure:
core-cn,text,theme,use-direction,use-required-callback-warning - Safe-area ownership remains explicit: shell surfaces touching system edges opt into
SafeArea; components do not silently invent app-shell insets. - Web consumers load the BeeUI semantic theme CSS as documented in Web onboarding.
Platform behavior
Section titled “Platform behavior”This family has platform-split source files. The bundler selects the native/Web implementation; do not infer native runtime behavior from the Web preview.
- Web: live browser/keyboard behavior is verified by Web-specific checks where applicable.
- iOS / Android: package/export/native compile evidence is not described as device-runtime proof. Consult the compatibility and native-preview guides for the exact evidence class.
- Platform-specific or experimental behavior is called out in the canonical component/compatibility docs rather than hidden behind a generic parity claim.
Accessibility
Section titled “Accessibility”Use the Accessibility overview, RTL/localization, and Large text & zoom alongside this family. Roles/states, keyboard/focus behavior, announcements, Dynamic Type/Web zoom, RTL, and reduced-motion expectations remain component-specific; BeeUI does not claim universal accessibility certification from automated tests.
Styling and theming
Section titled “Styling and theming”BeeUI components consume semantic tokens and support the current typed variant/density contracts. Use Theming and Density. className is an implementation escape hatch for source-owned/application work, not a cross-engine portability guarantee.
Executable examples
Section titled “Executable examples”- Primary executable fixture:
apps/showcase/__tests__/dynamic-type-contract.test.tsx - Additional fixture:
apps/showcase/__tests__/perf-render-commit.test.tsx - Additional fixture:
apps/showcase/__tests__/table-performance.test.tsx - Additional fixture:
apps/showcase/__tests__/table.test.tsx
Open the matching Web runtime in Showcase. The Showcase link demonstrates Web behavior; use the native-preview guide for real simulator/emulator/device paths.
Live Web preview
Section titled “Live Web preview”This frame loads the real BeeUI Web Showcase on demand; it is not a second docs-only implementation. It proves browser behavior only. Use native preview for iOS/Android simulator, emulator or device paths.
Composition anatomy
Section titled “Composition anatomy”- Family root / primary export:
Table- Public composition parts / helpers:
TableBodyTableCaptionTableCellTableFooterTableHeadTableHeaderTableRow
- Exported type surface:
TableBodyPropsTableCaptionPropsTableCellPropsTableFooterPropsTableHeaderPropsTableHeadPropsTableLayoutTablePropsTableRowPropsTableSortDirection
- Public composition parts / helpers:
The tree above is ordinary document structure so it remains readable with keyboard and assistive technology; it is derived from the real public export family rather than a canvas-only diagram.
Verified example source
Section titled “Verified example source”The following is the exact typechecked runtime Showcase fixture selected for this live preview: apps/showcase/component-gallery/table-showcase.tsx. Runtime gallery/pattern sources are preferred over test harnesses, and the displayed source and executable source are the same file; there is no separately maintained demo snippet.
import { Badge, Card, Checkbox, IconButton, Section, Table, TableBody, TableCaption, TableCell, TableHead, TableHeader, TableRow, Text, VStack, type TableSortDirection,} from '@beemvp/beeui-ui';import * as React from 'react';
type TeamMember = { id: string; name: string; role: string; status: 'Active' | 'Invited';};
const TEAM_MEMBERS: TeamMember[] = [ { id: 'ada', name: 'Ada Lovelace', role: 'Engineering', status: 'Active' }, { id: 'grace', name: 'Grace Hopper', role: 'Engineering', status: 'Active' }, { id: 'alan', name: 'Alan Turing', role: 'Research', status: 'Invited' },];
// Real, caller-owned sort — proves `TableHead`'s `sortDirection`/`onSortChange`// contract drives actual row order rather than a purely decorative indicator// (ADR-007 "State boundaries": Table stores no sort state itself).function sortByName(rows: TeamMember[], direction: TableSortDirection): TeamMember[] { if (direction === 'none') return rows; const sorted = [...rows].sort((a, b) => a.name.localeCompare(b.name)); return direction === 'descending' ? sorted.reverse() : sorted;}
function nextSortDirection(current: TableSortDirection): TableSortDirection { if (current === 'none') return 'ascending'; if (current === 'ascending') return 'descending'; return 'none';}
function TeamTable({ layout }: { layout?: 'scroll' | 'stacked' }) { const [sortDirection, setSortDirection] = React.useState<TableSortDirection>('none'); const [selectedIds, setSelectedIds] = React.useState<Set<string>>(new Set());
const rows = React.useMemo(() => sortByName(TEAM_MEMBERS, sortDirection), [sortDirection]); const allSelected = selectedIds.size === TEAM_MEMBERS.length; const someSelected = selectedIds.size > 0 && !allSelected;
const setRowSelected = (id: string, selected: boolean) => { setSelectedIds((previous) => { const next = new Set(previous); if (selected) next.add(id); else next.delete(id); return next; }); };
return ( <VStack gap="sm"> <Table layout={layout}> <TableCaption>Team members</TableCaption> <TableHeader> <TableRow> <TableHead label="Select all"> <Checkbox accessibilityLabel="Select all team members" checked={allSelected ? true : someSelected ? 'indeterminate' : false} onCheckedChange={(checked) => setSelectedIds(checked ? new Set(TEAM_MEMBERS.map((member) => member.id)) : new Set()) } /> </TableHead> <TableHead onSortChange={() => setSortDirection(nextSortDirection(sortDirection))} sortDirection={sortDirection}> Name </TableHead> <TableHead>Role</TableHead> <TableHead>Status</TableHead> <TableHead label="Actions">Actions</TableHead> </TableRow> </TableHeader> <TableBody> {rows.map((member) => ( <TableRow key={member.id} selected={selectedIds.has(member.id)}> <TableCell label="Select"> <Checkbox accessibilityLabel={`Select ${member.name}`} checked={selectedIds.has(member.id)} onCheckedChange={(checked) => setRowSelected(member.id, checked)} /> </TableCell> <TableCell>{member.name}</TableCell> <TableCell>{member.role}</TableCell> <TableCell> <Badge variant={member.status === 'Active' ? 'success' : 'secondary'}> {member.status} </Badge> </TableCell> <TableCell label="Actions"> <IconButton accessibilityLabel={`Edit ${member.name}`} variant="ghost"> ✎ </IconButton> </TableCell> </TableRow> ))} </TableBody> </Table> <Text tone="muted" variant="caption"> {`Sort: ${sortDirection} · Selected: ${selectedIds.size}`} </Text> </VStack> );}
export function TableShowcase() { return ( <VStack gap="lg"> <Card className="gap-4" testID="table-showcase" variant="raised"> <Section description="Real HTML table/th-scope semantics, a keyboard-reachable sort trigger in normal tab order, and caller-owned row selection via Checkbox (ADR-007)." title="Sortable, selectable table" > <TeamTable /> </Section> </Card>
<Card className="gap-4" testID="table-showcase-stacked"> <Section description="Explicit opt-in card/label-value presentation for narrow viewports — the same composed rows, no duplicated `.map()` loop." title="Stacked layout" > <TeamTable layout="stacked" /> </Section> </Card> </VStack> );}Use the code block’s copy affordance to copy the exact fixture. For a smaller app-specific example, start from the public imports shown above and keep only the state your screen owns.
Limitations
Section titled “Limitations”No component-specific limitation is curated here. Check Compatibility and the linked behavior contract for target-specific constraints.
Implementation note: Platform-split; see docs/data-typography.md for data-cell typography.