Save and restore grid state in localStorage.
State persistence saves the grid's state (sorting, filtering, column visibility, etc.) to localStorage. When users return, their preferences are automatically restored.
<ActiveGrid
gridId="users"
enablePersistence={true}
columns={columns}
data={data}
{...}
/>Enable persistence with a unique gridId:
<ActiveGrid
gridId="users-grid" // Required for persistence
enablePersistence={true}
columns={columns}
data={data}
{...}
/>The gridId prop is required when enablePersistence is true. It serves as the localStorage key.
The following state is automatically saved:
State is stored in localStorage with the key:
ActiveGrid-state-{gridId}For example:
gridId="users" → localStorage key: "ActiveGrid-state-users"localStorage.removeItem('ActiveGrid-state-users');function UsersTable() {
const handleReset = () => {
localStorage.removeItem('ActiveGrid-state-users');
window.location.reload();
};
return (
<>
<Button onClick={handleReset}>Reset Grid</Button>
<ActiveGrid
gridId="users"
enablePersistence={true}
{...}
/>
</>
);
}Include user ID in the gridId for per-user state:
Use different gridId values for different views:
While you can't selectively disable parts of persistence, you can control initial state:
When updating grid configuration, consider versioning:
This creates a new persistence key when the version changes.
Persistence works seamlessly with server mode:
You can use both persistence and URL sync:
URL parameters take precedence over persisted state.
localStorage is supported in:
localStorage has a limit of ~5-10 MB per domain. Grid state typically uses:
Thousands of grids can be stored before hitting limits.
State is stored locally in the user's browser and is not sent to the server. Users can clear it via browser settings.
To clear all persisted grid states:
gridIdgridId for different gridsgridId requirementExample persisted state:
Test your grid with and without persisted state:
For server-side user preferences:
const userId = useAuth().user.id;
<ActiveGrid
gridId={`users-${userId}`}
enablePersistence={true}
{...}
/>// Active users view
<ActiveGrid
gridId="users-active"
enablePersistence={true}
{...}
/>
// Inactive users view
<ActiveGrid
gridId="users-inactive"
enablePersistence={true}
{...}
/>// Force initial sort regardless of persistence
const [sorting, setSorting] = useState([
{ id: 'createdAt', desc: true }
]);
<ActiveGrid
gridId="users"
enablePersistence={true}
state={{ sorting }}
onSortingChange={setSorting}
{...}
/>const GRID_VERSION = 'v2';
<ActiveGrid
gridId={`users-${GRID_VERSION}`}
enablePersistence={true}
{...}
/>const storedState = localStorage.getItem('ActiveGrid-state-users');
console.log('Stored state:', JSON.parse(storedState || '{}'));useEffect(() => {
const handler = () => {
const state = localStorage.getItem('ActiveGrid-state-users');
console.log('State updated:', state);
};
window.addEventListener('storage', handler);
return () => window.removeEventListener('storage', handler);
}, []);import { useState } from 'react';
import { ActiveGrid } from '@workspace/active-grid';
function UsersTable() {
const userId = useAuth().user.id;
const gridId = `users-${userId}`;
const handleResetGrid = () => {
if (confirm('Reset all grid preferences?')) {
localStorage.removeItem(`ActiveGrid-state-${gridId}`);
window.location.reload();
}
};
return (
<div>
<div className="mb-4 flex justify-between">
<h1>Users</h1>
<Button variant="outline" onClick={handleResetGrid}>
Reset Grid
</Button>
</div>
<ActiveGrid
gridId={gridId}
enablePersistence={true}
columns={columns}
data={users}
pagination={{
enabled: true,
pageSizeOptions: [10, 25, 50, 100],
}}
/>
</div>
);
}<ActiveGrid
gridId="users"
mode="server"
fetchFn={fetchUsers}
enablePersistence={true}
columns={columns}
// Page size, filters, and sorting are persisted
{...}
/><ActiveGrid
gridId="users"
enablePersistence={true}
enableUrlSync={true}
columns={columns}
data={data}
{...}
/>Object.keys(localStorage)
.filter(key => key.startsWith('ActiveGrid-state-'))
.forEach(key => localStorage.removeItem(key));{
"columnVisibility": {
"email": false,
"phone": false
},
"columnOrder": ["name", "status", "createdAt"],
"columnSizing": {
"name": 200,
"status": 120
},
"columnPinning": {
"left": ["name"],
"right": []
},
"sorting": [
{ "id": "createdAt", "desc": true }
],
"columnFilters": [
{ "id": "status", "value": "active" }
],
"globalFilter": "search query",
"pagination": {
"pageIndex": 0,
"pageSize": 25
}
}describe('UsersTable', () => {
beforeEach(() => {
localStorage.clear();
});
it('loads with default state', () => {
render(<UsersTable />);
// Assert default state
});
it('restores persisted state', () => {
localStorage.setItem('ActiveGrid-state-users', JSON.stringify({
sorting: [{ id: 'name', desc: false }],
}));
render(<UsersTable />);
// Assert restored state
});
});type User = {
id: string;
name: string;
};
<ActiveGrid<User>
gridId="users"
enablePersistence={true}
columns={columns}
data={users}
{...}
/>function UsersTable() {
const [userPrefs, setUserPrefs] = useState(null);
// Load preferences from server
useEffect(() => {
api.getUserPreferences('users-grid').then(setUserPrefs);
}, []);
// Save preferences to server
const handleStateChange = (state) => {
api.saveUserPreferences('users-grid', state);
};
return (
<ActiveGrid
gridId="users"
state={userPrefs}
// ... handle state changes
{...}
/>
);
}