Events fired by columns.
Column events allow you to respond to user interactions with columns. Handle sorting changes, filtering updates, visibility toggles, resizing, and more.
<ActiveGrid
onSortingChange={(sorting) => console.log('Sorting changed:', sorting)}
onColumnFiltersChange={(filters) => console.log('Filters changed:', filters)}
onColumnVisibilityChange={(visibility) => console.log('Visibility changed:', visibility)}
{...}
/>Triggered when column sorting changes.
import { SortingState } from '@tanstack/react-table';
<ActiveGrid
onSortingChange={(updater: SortingState | ((old: SortingState) => SortingState)) => {
if (typeof updater === 'function') {
setSorting(prev => updater(prev));
} else {
setSorting(updater);
}
}}
{...}
/>Type:
type SortingState = Array<{
id: string;
desc: boolean;
}>;Example:
import { useState } from 'react';
import { SortingState } from '@tanstack/react-table';
function SortableTable() {
const [sorting, setSorting] = useState<SortingState>([]);
return (
<ActiveGrid
state={{ sorting }}
onSortingChange={setSorting}
columns={columns}
data={data}
/>
);
}Triggered when column filters change.
import { ColumnFiltersState } from '@tanstack/react-table';
<ActiveGrid
onColumnFiltersChange={(updater) => {
if (typeof updater === 'function') {
setFilters(prev => updater(prev));
} else {
setFilters(updater);
}
}}
{...}
/>Type:
type ColumnFiltersState = Array<{
id: string;
value: unknown;
}>;Example:
function FilterableTable() {
const [columnFilters, setColumnFilters] = useState<ColumnFiltersState>([]);
return (
<ActiveGrid
state={{ columnFilters }}
onColumnFiltersChange={setColumnFilters}
columns={columns}
data={data}
/>
);
}Triggered when column visibility changes.
import { VisibilityState } from '@tanstack/react-table';
<ActiveGrid
onColumnVisibilityChange={(updater) => {
setColumnVisibility(updater);
}}
{...}
/>Type:
type VisibilityState = Record<string, boolean>;Example:
function TableWithHiddenColumns() {
const [columnVisibility, setColumnVisibility] = useState<VisibilityState>({
email: false, // Hide email column by default
});
return (
<ActiveGrid
state={{ columnVisibility }}
onColumnVisibilityChange={setColumnVisibility}
columns={columns}
data={data}
/>
);
}Triggered when column sizes change.
import { ColumnSizingState } from '@tanstack/react-table';
<ActiveGrid
onColumnSizingChange={(updater) => {
setColumnSizing(updater);
}}
columnResizeMode="onChange" // or "onEnd"
{...}
/>Type:
type ColumnSizingState = Record<string, number>;Example:
function ResizableTable() {
const [columnSizing, setColumnSizing] = useState<ColumnSizingState>({});
return (
<ActiveGrid
state={{ columnSizing }}
onColumnSizingChange={setColumnSizing}
columnResizeMode="onEnd"
columns={columns}
data={data}
/>
);
}Triggered when column order changes.
import { ColumnOrderState } from '@tanstack/react-table';
<ActiveGrid
onColumnOrderChange={(updater) => {
setColumnOrder(updater);
}}
{...}
/>Type:
type ColumnOrderState = string[];Example:
function ReorderableTable() {
const [columnOrder, setColumnOrder] = useState<ColumnOrderState>([]);
return (
<ActiveGrid
state={{ columnOrder }}
onColumnOrderChange={setColumnOrder}
columns={columns}
data={data}
/>
);
}Triggered when column pinning changes.
import { ColumnPinningState } from '@tanstack/react-table';
<ActiveGrid
onColumnPinningChange={(updater) => {
setColumnPinning(updater);
}}
{...}
/>Type:
type ColumnPinningState = {
left?: string[];
right?: string[];
};Example:
function PinnableTable() {
const [columnPinning, setColumnPinning] = useState<ColumnPinningState>({
left: ['name'],
right: ['actions'],
});
return (
<ActiveGrid
state={{ columnPinning }}
onColumnPinningChange={setColumnPinning}
columns={columns}
data={data}
/>
);
}import { useState } from 'react';
import {
SortingState,
ColumnFiltersState,
VisibilityState,
ColumnSizingState,
ColumnOrderState,
ColumnPinningState,
} from '@tanstack/react-table';
function FullyControlledTable() {
const [sorting, setSorting] = useState<SortingState>([]);
const [columnFilters, setColumnFilters] = useState<ColumnFiltersState>([]);
const [columnVisibility, setColumnVisibility] = useState<VisibilityState>({});
const [columnSizing, setColumnSizing] = useState<ColumnSizingState>({});
const [columnOrder, setColumnOrder] = useState<ColumnOrderState>([]);
const [columnPinning, setColumnPinning] = useState<ColumnPinningState>({});
return (
<ActiveGrid
state={{
sorting,
columnFilters,
columnVisibility,
columnSizing,
columnOrder,
columnPinning,
}}
onSortingChange={setSorting}
onColumnFiltersChange={setColumnFilters}
onColumnVisibilityChange={setColumnVisibility}
onColumnSizingChange={setColumnSizing}
onColumnOrderChange={setColumnOrder}
onColumnPinningChange={setColumnPinning}
columns={columns}
data={data}
/>
);
}All column events use the "updater" pattern:
function TableWithPersistedSorting() {
const [sorting, setSorting] = useState<SortingState>(() => {
const saved = localStorage.getItem('table-sorting');
return saved ? JSON.parse(saved) : [];
});
const handleSortingChange = (updater: any) => {
setSorting(prev => {
const newSorting = typeof updater === 'function' ? updater(prev) : updater;
localStorage.setItem('table-sorting', JSON.stringify(newSorting));
return newSorting;
});
};
return (
<ActiveGrid
state={{ sorting }}
onSortingChange={handleSortingChange}
{...}
/>
);
}function AnalyticsTable() {
const handleFilterChange = (updater: any) => {
setColumnFilters(prev => {
const newFilters = typeof updater === 'function' ? updater(prev) : updater;
// Track analytics
analytics.track('Table Filtered', {
filters: newFilters,
timestamp: new Date(),
});
return newFilters;
});
};
return (
<ActiveGrid
onColumnFiltersChange={handleFilterChange}
{...}
/>
);
}import { useSearchParams } from 'next/navigation';
function URLSyncedTable() {
const searchParams = useSearchParams();
const [sorting, setSorting] = useState<SortingState>(() => {
const sortParam = searchParams.get('sort');
return sortParam ? JSON.parse(sortParam) : [];
});
const handleSortingChange = (updater: any) => {
setSorting(prev => {
const newSorting = typeof updater === 'function' ? updater(prev) : updater;
// Update URL
const params = new URLSearchParams(searchParams);
if (newSorting.length > 0) {
params.set('sort', JSON.stringify(newSorting));
} else {
params.delete('sort');
}
window.history.pushState(null, '', `?${params.toString()}`);
return newSorting;
});
};
return (
<ActiveGrid
state={{ sorting }}
onSortingChange={handleSortingChange}
{...}
/>
);
}function VisibilityControlledTable() {
const [columnVisibility, setColumnVisibility] = useState<VisibilityState>({
id: false,
createdAt: false,
});
const toggleColumn = (columnId: string) => {
setColumnVisibility(prev => ({
...prev,
[columnId]: !prev[columnId],
}));
};
return (
<>
<div className="mb-4 flex gap-2">
<Button onClick={() => toggleColumn('id')}>
Toggle ID
</Button>
<Button onClick={() => toggleColumn('createdAt')}>
Toggle Created Date
</Button>
</div>
<ActiveGrid
state={{ columnVisibility }}
onColumnVisibilityChange={setColumnVisibility}
columns={columns}
data={data}
/>
</>
);
}function ServerSyncedFilters() {
const [columnFilters, setColumnFilters] = useState<ColumnFiltersState>([]);
const handleFilterChange = async (updater: any) => {
const newFilters = typeof updater === 'function'
? updater(columnFilters)
: updater;
setColumnFilters(newFilters);
// Trigger server refetch with new filters
await refetchData({
filters: newFilters,
});
};
return (
<ActiveGrid
mode="server"
state={{ columnFilters }}
onColumnFiltersChange={handleFilterChange}
{...}
/>
);
}import { useDebouncedCallback } from 'use-debounce';
function DebouncedFilterTable() {
const [columnFilters, setColumnFilters] = useState<ColumnFiltersState>([]);
const debouncedRefetch = useDebouncedCallback(
(filters: ColumnFiltersState) => {
refetchData({ filters });
},
300
);
const handleFilterChange = (updater: any) => {
const newFilters = typeof updater === 'function'
? updater(columnFilters)
: updater;
setColumnFilters(newFilters);
debouncedRefetch(newFilters);
};
return (
<ActiveGrid
state={{ columnFilters }}
onColumnFiltersChange={handleFilterChange}
{...}
/>
);
}import { useState, useEffect } from 'react';
import {
ActiveGrid,
GridColumnDef,
} from '@workspace/active-grid';
import {
SortingState,
ColumnFiltersState,
VisibilityState,
} from '@tanstack/react-table';
type Product = {
id: string;
name: string;
price: number;
category: string;
};
function ProductsTable() {
// Column state
const [sorting, setSorting] = useState<SortingState>([]);
const [columnFilters, setColumnFilters] = useState<ColumnFiltersState>([]);
const [columnVisibility, setColumnVisibility] = useState<VisibilityState>({});
// Persist to localStorage
useEffect(() => {
localStorage.setItem('products-sorting', JSON.stringify(sorting));
}, [sorting]);
useEffect(() => {
localStorage.setItem('products-filters', JSON.stringify(columnFilters));
}, [columnFilters]);
// Track analytics
const handleSortingChange = (updater: any) => {
setSorting(prev => {
const newSorting = typeof updater === 'function' ? updater(prev) : updater;
analytics.track('Products Sorted', {
sorting: newSorting,
});
return newSorting;
});
};
const handleFilterChange = (updater: any) => {
setColumnFilters(prev => {
const newFilters = typeof updater === 'function' ? updater(prev) : updater;
analytics.track('Products Filtered', {
filters: newFilters,
});
return newFilters;
});
};
const columns: GridColumnDef<Product>[] = [
{
accessorKey: 'name',
header: 'Product',
},
{
accessorKey: 'price',
header: 'Price',
meta: {
filterType: 'number',
},
},
{
accessorKey: 'category',
header: 'Category',
meta: {
filterType: 'select',
},
},
];
return (
<ActiveGrid
columns={columns}
data={products}
state={{
sorting,
columnFilters,
columnVisibility,
}}
onSortingChange={handleSortingChange}
onColumnFiltersChange={handleFilterChange}
onColumnVisibilityChange={setColumnVisibility}
/>
);
}type Updater<T> = T | ((old: T) => T);
// Handle both direct values and functions
const handleChange = (updater: Updater<State>) => {
setState(prev => {
return typeof updater === 'function' ? updater(prev) : updater;
});
};import {
SortingState,
ColumnFiltersState,
VisibilityState,
ColumnSizingState,
ColumnOrderState,
ColumnPinningState,
Updater,
} from '@tanstack/react-table';
// Type-safe event handlers
const handleSortingChange = (updater: Updater<SortingState>) => {
setSorting(prev =>
typeof updater === 'function' ? updater(prev) : updater
);
};
const handleFilterChange = (updater: Updater<ColumnFiltersState>) => {
setFilters(prev =>
typeof updater === 'function' ? updater(prev) : updater
);
};