VitalGrid Compound Components Guide
This guide shows how to use the VitalGrid compound components to build table UIs.
This guide shows how to use the VitalGrid compound components to build table UIs.
It focuses on what you can do, in simple terms:
- Render a virtualized table
- Plug in your data source
- Add toolbar actions
- Control system columns (select, drag, add column)
- Customize layout without touching low-level table code
For deeper internals, see:
- Concepts Guide
- API Reference
- Architecture docs (for maintainers)
1. Overview
When you use VitalGrid the recommended way, you:
-
Create a factory once with
createVitalGrid. -
Use the factory hook in your component:
VitalGrid.useVitalGrid(...). -
Wrap your UI with the provider:
<VitalGrid.Provider ...>. -
Build your layout with compound components:
<VitalGrid.Root><VitalGrid.Toolbar><VitalGrid.Columns>(and friends)<VitalGrid.Header><VitalGrid.Body><VitalGrid.BodyCell>(for custom cells)
The compound components are:
- Higher-level building blocks
- Already wired to TanStack Table and your data source through context
- Safe to compose without worrying about internal table wiring
2. Basic layout
Here is the minimal pattern with factory + provider + compound components.
"use client";
import { createVitalGrid } from "@/vital-grid.js";
import { useLocalStorageDataSource } from "@/lib/data-sources/local.js";
// 1. Create factory once (module scope)
const VitalGrid = createVitalGrid({
features: {
sorting: true,
filtering: true,
columnResizing: true,
virtualization: true,
columnReordering: true,
rowReordering: true,
views: true,
},
});
// 2. Use factory + data source inside a component
export function BasicCompoundExample() {
const dataSource = useLocalStorageDataSource("compound-basic");
const { grid } = VitalGrid.useVitalGrid({
dataSource,
data: dataSource.rows.current,
columns: dataSource.columns.current.map(VitalGrid.createColumnDef),
});
// 3. Layout with Provider + compound components
return (
<VitalGrid.Provider grid={grid} workspaceId="compound-basic" height={480}>
<VitalGrid.Root height={480}>
<VitalGrid.Toolbar showViewControls={grid.features.views} />
<VitalGrid.Header />
<VitalGrid.Body />
</VitalGrid.Root>
</VitalGrid.Provider>
);
}Key points:
- You do not pass
tablemanually. - You do not call TanStack
useReactTableyourself. - The compound components read everything they need from context.
3. Toolbar and slots
Use Toolbar to add actions above your table.
<VitalGrid.Root height={480}>
<VitalGrid.Toolbar showViewControls={grid.features.views}>
{/* Left slot: common actions */}
<VitalGrid.Toolbar.Slot name="left">
<button onClick={refresh}>Refresh</button>
</VitalGrid.Toolbar.Slot>
{/* Center slot: you can use this for status text */}
<VitalGrid.Toolbar.Slot name="center">
<span>{rowsCount} rows</span>
</VitalGrid.Toolbar.Slot>
{/* Right slot: secondary actions */}
<VitalGrid.Toolbar.Slot name="right">
<button onClick={exportData}>Export</button>
</VitalGrid.Toolbar.Slot>
</VitalGrid.Toolbar>
<VitalGrid.Header />
<VitalGrid.Body />
</VitalGrid.Root>Notes:
showViewControls:- When
true, built-in view controls can show, if your data source supports views. - Safe to tie to
grid.features.views.
- When
- Slots:
name="left" | "center" | "right".- Use them to place buttons, filters, labels.
4. System columns with Columns (select, drag, add)
VitalGrid can show system columns, such as:
- Row selection checkbox
- Drag handle for row reordering
- "Add column" control
You control these with:
- Feature flags in your factory
- Data source capabilities
- The
Columnscompound components
4.1 Basic system columns configuration
<VitalGrid.Root height={480}>
<VitalGrid.Toolbar showViewControls={grid.features.views} />
<VitalGrid.Columns>
<VitalGrid.Columns.Left>
{/* Enable row selection column if supported */}
<VitalGrid.Columns.Select />
{/* Enable drag handle column for row reordering */}
<VitalGrid.Columns.Drag />
</VitalGrid.Columns.Left>
<VitalGrid.Columns.Right>
{/* Show "add column" control */}
<VitalGrid.Columns.Add />
</VitalGrid.Columns.Right>
</VitalGrid.Columns>
<VitalGrid.Header />
<VitalGrid.Body />
</VitalGrid.Root>What this means:
Columns.Left:- System columns rendered on the left side (select, drag).
Columns.Right:- System columns rendered on the right side (add).
- Actual behavior also depends on:
featuresfrom your factorycapabilitiesfrom your data source
If a feature or capability is off, the related system column will not appear even if you render the marker.
4.2 Permission-based system columns
const canSelectRows = currentUser.role === "admin";
const canReorderRows = currentUser.role === "editor";
const canAddColumns = currentUser.role === "admin";
<VitalGrid.Root height={480}>
<VitalGrid.Columns>
<VitalGrid.Columns.Left>
{canSelectRows && <VitalGrid.Columns.Select />}
{canReorderRows && <VitalGrid.Columns.Drag />}
</VitalGrid.Columns.Left>
<VitalGrid.Columns.Right>
{canAddColumns && <VitalGrid.Columns.Add />}
</VitalGrid.Columns.Right>
</VitalGrid.Columns>
<VitalGrid.Header />
<VitalGrid.Body />
</VitalGrid.Root>This is the main reason these components exist: simple, clear control over system behavior in JSX.
5. Custom cells with Body and BodyCell
You can let VitalGrid render the body, or you can customize it.
5.1 Default body
The simplest:
<VitalGrid.Root height={480}>
<VitalGrid.Toolbar showViewControls={grid.features.views} />
<VitalGrid.Header />
<VitalGrid.Body />
</VitalGrid.Root>Body:- Uses the internal configuration:
- Virtualization if enabled
- Row/column order from TanStack Table
- Field definitions for cells
- Uses the internal configuration:
5.2 Custom row rendering
Body can also take a render function.
<VitalGrid.Body>
{({ rows }) => (
<>
{rows.map((row) => (
<div key={row.id} className="flex border-b">
{row.getVisibleCells().map((cell) => (
<VitalGrid.BodyCell key={cell.id} cell={cell}>
{cell.column.id === "status" ? (
<span className="px-2 py-1 rounded bg-green-100 text-green-800 text-xs">
{String(cell.getValue() ?? "")}
</span>
) : (
String(cell.getValue() ?? "")
)}
</VitalGrid.BodyCell>
))}
</div>
))}
</>
)}
</VitalGrid.Body>Notes:
rowsandcellobjects come from TanStack Table.BodyCell:- Handles padding and interactions.
- Can render children you pass in.
- Still has access to the field registry and table via context.
Use this when you want custom HTML or styles but keep VitalGrid's behavior.
6. Common patterns
6.1 Always wrap in the provider
Good:
const { grid, VitalGridProvider } = VitalGrid.useVitalGrid({ ... });
return (
<VitalGridProvider grid={grid} workspaceId="x" height={480}>
<VitalGrid.Root height={480}>
<VitalGrid.Header />
<VitalGrid.Body />
</VitalGrid.Root>
</VitalGridProvider>
);Avoid:
- Rendering
Root,Header,Bodywithout the provider. - Creating your own table instance alongside VitalGrid's.
6.2 Use grid.features to drive UI
Use the features that VitalGrid resolves for you:
<VitalGrid.Toolbar showViewControls={grid.features.views}>
<VitalGrid.Toolbar.Slot name="right">
{grid.features.sorting && <button onClick={clearSort}>Clear sort</button>}
</VitalGrid.Toolbar.Slot>
</VitalGrid.Toolbar>This keeps your UI in sync with what the backend and factory actually support.
7. When to reach for compound components
Use VitalGrid compound components when:
- You want a fast, consistent table UI:
- Virtualized out of the box
- Drag and drop ready
- System columns included
- You do not want to manually wire:
- TanStack React Table
- Virtualization
- Data source capabilities
- Column metadata
They are designed so that:
- You focus on:
- Layout
- Buttons
- Content
- VitalGrid handles:
- Table engine
- State wiring
- Feature toggles
- Integration with your data source
If you ever feel you are redoing those things manually, you can lean more on these components.
API / Props
Use these as a quick reference for the main compound pieces.
VitalGridResult (factory output)
Prop
Type
VitalGridColumn
Prop
Type
Compound Components
Prop
Type
8. Summary
Root:- Main container and layout.
Toolbar(+Toolbar.Slot):- Top actions and view controls.
Columns(+Left,Right,Select,Drag,Add):- Configure system columns in JSX.
Header:- Renders column headers (with sorting/resizing when enabled).
Body:- Renders rows; supports defaults and custom render.
BodyCell:- Cell wrapper that plays nice with fields and editing.
Together, they give you a simple way to build an advanced grid:
- Virtualized
- Drag and drop
- Dynamic columns
- Backend-agnostic
without needing to think about low-level details every time.