VitalGrid
Guides

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:


1. Overview

When you use VitalGrid the recommended way, you:

  1. Create a factory once with createVitalGrid.

  2. Use the factory hook in your component: VitalGrid.useVitalGrid(...).

  3. Wrap your UI with the provider: <VitalGrid.Provider ...>.

  4. 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 table manually.
  • You do not call TanStack useReactTable yourself.
  • 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.
  • 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 Columns compound 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:
    • features from your factory
    • capabilities from 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

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:

  • rows and cell objects 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, Body without 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.