Composable UI
Seizen Table provides multiple levels of API abstraction. Choose the level that fits your needs—from zero-config to fully custom rendering.
Choosing an API Level
Section titled “Choosing an API Level”| Feature | Level 1 (High) | Level 2 (Mid) | Level 3 (Low) |
|---|---|---|---|
| Setup Complexity | Minimal | Moderate | High |
| Customization | Limited | High | Complete |
| Plugin Support | ✅ Yes | ✅ Yes | ❌ No |
| Context Menus | ✅ Yes | ✅ Yes | ❌ No |
| Layout Control | ❌ No | ✅ Yes | ✅ Yes |
| Best For | Quick setup | Custom layouts with plugins | Completely custom UI |
Level 1: High-Level API
Section titled “Level 1: High-Level API”The simplest approach—just pass a table instance and configuration:
import { SeizenTable, useSeizenTable } from "@izumisy/seizen-table";
function MyComponent() { const table = useSeizenTable({ data, columns }); return <SeizenTable table={table} paginate={{ enable: true }} />;}Level 2: Composable Components
Section titled “Level 2: Composable Components”Build custom layouts using composable components while keeping plugin support:
import { SeizenTable, SeizenTablePlugins, useSeizenTable } from "@izumisy/seizen-table";
function MyComponent() { const table = useSeizenTable({ data, columns, plugins: [MyPlugin] });
return ( <SeizenTable.Root table={table}> <SeizenTablePlugins.SidePanel position="left" /> <SeizenTable.Content> <SeizenTablePlugins.Header /> <SeizenTable.Table> <SeizenTable.Header /> <SeizenTable.Body /> </SeizenTable.Table> <SeizenTablePlugins.Footer /> <SeizenTable.Paginator sizeOptions={[10, 25, 50]} /> </SeizenTable.Content> <SeizenTablePlugins.SidePanel position="right" /> </SeizenTable.Root> );}Level 3: Low-Level API (TanStack Table Direct)
Section titled “Level 3: Low-Level API (TanStack Table Direct)”For maximum control, use TanStack Table API directly:
import { useSeizenTable, flexRender } from "@izumisy/seizen-table";
function CustomTable({ data, columns }) { const table = useSeizenTable({ data, columns }); const tanstack = table._tanstackTable;
return ( <table> <thead> {tanstack.getHeaderGroups().map((headerGroup) => ( <tr key={headerGroup.id}> {headerGroup.headers.map((header) => ( <th key={header.id}> {flexRender(header.column.columnDef.header, header.getContext())} </th> ))} </tr> ))} </thead> <tbody> {tanstack.getRowModel().rows.map((row) => ( <tr key={row.id}> {row.getVisibleCells().map((cell) => ( <td key={cell.id}> {flexRender(cell.column.columnDef.cell, cell.getContext())} </td> ))} </tr> ))} </tbody> </table> );}Component Reference
Section titled “Component Reference”SeizenTable Components
Section titled “SeizenTable Components”Core table structure components:
| Component | HTML Element | Description |
|---|---|---|
SeizenTable.Root | <div> | Provider wrapper (required, provides context) |
SeizenTable.Content | <div> | Main content area (between side panels) |
SeizenTable.Table | <div> + <table> | Table wrapper with scrollable container |
SeizenTable.Header | <thead> | Column headers with sorting and context menu |
SeizenTable.Body | <tbody> | Row rendering with render props support |
SeizenTable.Row | <tr> | Individual row with click handlers |
SeizenTable.Cell | <td> | Individual cell with context menu support |
SeizenTable.Paginator | <div> | Pagination controls |
SeizenTable.Loader | <div> | Loading overlay for Remote Mode |
SeizenTablePlugins
Section titled “SeizenTablePlugins”Plugin-provided UI slots:
| Component | Description |
|---|---|
SeizenTablePlugins.SidePanel | Left/right side panels for plugin content |
SeizenTablePlugins.Header | Plugin header slots (e.g., filter bars) |
SeizenTablePlugins.Footer | Plugin footer slots |
SeizenTablePlugins.InlineRow | Expandable row content (e.g., row details) |
SeizenTablePlugins.Cell | Custom cell rendering from plugins |
Component Hierarchy
Section titled “Component Hierarchy”SeizenTable.Root (providers + context)├─ SeizenTablePlugins.SidePanel (position: "left")├─ SeizenTable.Content (main content area)│ ├─ SeizenTablePlugins.Header (plugin-provided toolbars)│ ├─ SeizenTable.Table│ │ ├─ SeizenTable.Loader (optional, via `before` prop)│ │ ├─ SeizenTable.Header│ │ └─ SeizenTable.Body│ │ ├─ SeizenTable.Row│ │ │ └─ SeizenTable.Cell│ │ └─ SeizenTablePlugins.InlineRow (plugin-provided expandable rows)│ ├─ SeizenTablePlugins.Footer (plugin-provided footers)│ └─ SeizenTable.Paginator└─ SeizenTablePlugins.SidePanel (position: "right")Loading Overlay
Section titled “Loading Overlay”For Remote Mode, use SeizenTable.Loader to show a loading state while fetching data:
const [isLoading, setIsLoading] = useState(false);
<SeizenTable.Table before={<SeizenTable.Loader loading={isLoading} />}> <SeizenTable.Header /> <SeizenTable.Body /></SeizenTable.Table>Custom loader component:
<SeizenTable.Table before={ <SeizenTable.Loader loading={isLoading}> <MyCustomSpinner /> </SeizenTable.Loader> }> <SeizenTable.Header /> <SeizenTable.Body /></SeizenTable.Table>Customization
Section titled “Customization”Custom Row Rendering
Section titled “Custom Row Rendering”SeizenTable.Body supports render props for custom row rendering:
<SeizenTable.Body> {(row) => ( <> <SeizenTable.Row row={row} className={row.original.isVIP ? "vip-row" : ""} onClick={(row) => console.log("Clicked:", row.original)} /> <SeizenTablePlugins.InlineRow row={row} colSpan={row.getVisibleCells().length} /> </> )}</SeizenTable.Body>When no children are provided, SeizenTable.Body automatically renders SeizenTable.Row and SeizenTablePlugins.InlineRow for each row.
Opting out of InlineRow:
<SeizenTable.Body> {(row) => <SeizenTable.Row row={row} />}</SeizenTable.Body>Custom Cell Content
Section titled “Custom Cell Content”SeizenTable.Cell supports custom children:
// Default: uses plugin Cell automatically<SeizenTable.Cell cell={cell} row={row} />
// Custom content without plugin support<SeizenTable.Cell cell={cell} row={row}> <span className="custom">{cell.getValue()}</span></SeizenTable.Cell>
// Custom content with plugin support<SeizenTable.Cell cell={cell} row={row}> <SeizenTablePlugins.Cell cell={cell} column={cell.column} row={row}> <span className="custom">{cell.getValue()}</span> </SeizenTablePlugins.Cell></SeizenTable.Cell>Adding Custom Elements
Section titled “Adding Custom Elements”You can add custom elements anywhere in the layout:
<SeizenTable.Root table={table}> <SeizenTablePlugins.SidePanel position="left" /> <SeizenTable.Content> {/* Custom toolbar */} <div className="custom-toolbar"> <button>Export</button> <button>Refresh</button> </div>
<SeizenTablePlugins.Header />
<SeizenTable.Table> <SeizenTable.Header /> <SeizenTable.Body /> </SeizenTable.Table>
<SeizenTablePlugins.Footer />
{/* Custom footer content */} <div className="table-info"> Showing {table.getData().length} records </div>
<SeizenTable.Paginator /> </SeizenTable.Content> <SeizenTablePlugins.SidePanel position="right" /></SeizenTable.Root>Advanced: Using Hooks
Section titled “Advanced: Using Hooks”For completely custom rendering while keeping context menu support, use the provided hooks inside SeizenTable.Root.
Available Hooks
Section titled “Available Hooks”| Hook | Description |
|---|---|
useSeizenTableContext() | Get the table instance from context |
useContextMenu() | Get handleCellContextMenu and handleColumnContextMenu functions |
Example
Section titled “Example”import { SeizenTable, useSeizenTableContext, useContextMenu, flexRender} from "@izumisy/seizen-table";
function CustomTableBody() { const table = useSeizenTableContext(); const { handleCellContextMenu } = useContextMenu();
return ( <> {table._tanstackTable.getRowModel().rows.map((row) => ( <tr key={row.id} onClick={() => table.eventBus.emit("row-click", row.original)} > {row.getVisibleCells().map((cell) => ( <td key={cell.id} onContextMenu={(e) => handleCellContextMenu(e, cell, cell.column, row) } > {flexRender(cell.column.columnDef.cell, cell.getContext())} </td> ))} </tr> ))} </> );}
// Usage (must be inside SeizenTable.Root)<SeizenTable.Root table={table}> <SeizenTable.Content> <SeizenTable.Table> <SeizenTable.Header /> <tbody> <CustomTableBody /> </tbody> </SeizenTable.Table> </SeizenTable.Content></SeizenTable.Root>