NuGrid can automatically persist and restore grid state, including column sizes, sorting, filters, and more.
Enable state persistence with the state-persistence prop:
<template>
<NuGrid
:data="data"
:columns="columns"
:state-persistence="{
key: 'my-grid',
storage: 'local',
}"
/>
</template>
interface StatePersistenceOptions {
key: string
storage: 'local' | 'session' | 'custom'
include?: string[]
exclude?: string[]
debounce?: number
onSave?: (state: any) => void
onLoad?: (state: any) => any
}
| Option | Type | Default | Description |
|---|---|---|---|
key | string | required | Storage key |
storage | 'local' | 'session' | 'custom' | 'local' | Storage type |
include | string[] | All state | State keys to persist |
exclude | string[] | None | State keys to exclude |
debounce | number | 300 | Debounce delay (ms) |
onSave | function | - | Called before saving |
onLoad | function | - | Called after loading |
By default, the following state is persisted:
Persist only specific state:
<template>
<!-- Only persist column sizes and sorting -->
<NuGrid
:data="data"
:columns="columns"
:state-persistence="{
key: 'my-grid',
include: ['columnSizing', 'sorting'],
}"
/>
<!-- Persist everything except filters -->
<NuGrid
:data="data"
:columns="columns"
:state-persistence="{
key: 'my-grid',
exclude: ['columnFilters'],
}"
/>
</template>
Persists across browser sessions:
<template>
<NuGrid
:data="data"
:columns="columns"
:state-persistence="{
key: 'my-grid',
storage: 'local',
}"
/>
</template>
Persists only for the current session:
<template>
<NuGrid
:data="data"
:columns="columns"
:state-persistence="{
key: 'my-grid',
storage: 'session',
}"
/>
</template>
Use your own storage mechanism:
<script setup lang="ts">
const customStorage = {
getItem: (key: string) => {
// Load from your storage (API, IndexedDB, etc.)
return myCustomStorage.get(key)
},
setItem: (key: string, value: string) => {
// Save to your storage
myCustomStorage.set(key, value)
},
removeItem: (key: string) => {
myCustomStorage.delete(key)
},
}
</script>
<template>
<NuGrid
:data="data"
:columns="columns"
:state-persistence="{
key: 'my-grid',
storage: 'custom',
customStorage,
}"
/>
</template>
Modify state before saving or after loading:
<script setup lang="ts">
const persistenceOptions = {
key: 'my-grid',
onSave: (state) => {
// Add metadata
return {
...state,
savedAt: Date.now(),
version: '1.0',
}
},
onLoad: (state) => {
// Migrate old state format
if (!state.version) {
return migrateOldState(state)
}
return state
},
}
</script>
<template>
<NuGrid
:data="data"
:columns="columns"
:state-persistence="persistenceOptions"
/>
</template>
For full control, manage state manually:
<script setup lang="ts">
const STORAGE_KEY = 'my-grid-state'
// Load state on mount
const savedState = JSON.parse(
localStorage.getItem(STORAGE_KEY) || '{}'
)
const columnSizing = ref(savedState.columnSizing ?? {})
const sorting = ref(savedState.sorting ?? [])
const columnFilters = ref(savedState.columnFilters ?? [])
// Save state on change
watchDebounced(
[columnSizing, sorting, columnFilters],
() => {
localStorage.setItem(STORAGE_KEY, JSON.stringify({
columnSizing: columnSizing.value,
sorting: sorting.value,
columnFilters: columnFilters.value,
}))
},
{ debounce: 500, deep: true }
)
// Reset state
function resetState() {
localStorage.removeItem(STORAGE_KEY)
columnSizing.value = {}
sorting.value = []
columnFilters.value = []
}
</script>
<template>
<div>
<UButton @click="resetState">Reset Layout</UButton>
<NuGrid
v-model:column-sizing="columnSizing"
v-model:sorting="sorting"
v-model:column-filters="columnFilters"
:data="data"
:columns="columns"
/>
</div>
</template>
Provide a way to reset persisted state:
<script setup lang="ts">
const gridRef = useTemplateRef('grid')
function resetGridState() {
// Clear storage
localStorage.removeItem('my-grid')
// Reset grid state
gridRef.value?.resetState()
}
</script>
<template>
<div>
<UButton variant="outline" @click="resetGridState">
Reset to Defaults
</UButton>
<NuGrid
ref="grid"
:data="data"
:columns="columns"
:state-persistence="{ key: 'my-grid' }"
/>
</div>
</template>
Store state per user:
<script setup lang="ts">
const user = useAuth().user
const persistenceKey = computed(() =>
`grid-state-${user.value?.id ?? 'anonymous'}`
)
</script>
<template>
<NuGrid
:data="data"
:columns="columns"
:state-persistence="{
key: persistenceKey,
storage: 'local',
}"
/>
</template>
<script setup lang="ts">
const gridRef = useTemplateRef('grid')
const toast = useToast()
const persistenceOptions = {
key: 'products-grid',
storage: 'local',
include: ['columnSizing', 'columnOrder', 'sorting', 'columnPinning'],
debounce: 500,
onSave: (state) => {
console.log('Saving state:', state)
return state
},
onLoad: (state) => {
if (state) {
toast.add({
title: 'Layout restored',
color: 'info',
})
}
return state
},
}
function resetLayout() {
localStorage.removeItem('products-grid')
window.location.reload()
}
function exportLayout() {
const state = localStorage.getItem('products-grid')
if (state) {
navigator.clipboard.writeText(state)
toast.add({ title: 'Layout copied', color: 'success' })
}
}
function importLayout() {
const input = prompt('Paste layout JSON:')
if (input) {
try {
JSON.parse(input) // Validate
localStorage.setItem('products-grid', input)
window.location.reload()
} catch {
toast.add({ title: 'Invalid layout', color: 'error' })
}
}
}
</script>
<template>
<div class="space-y-4">
<div class="flex gap-2">
<UButton variant="outline" @click="resetLayout">
Reset Layout
</UButton>
<UButton variant="outline" @click="exportLayout">
Export Layout
</UButton>
<UButton variant="outline" @click="importLayout">
Import Layout
</UButton>
</div>
<NuGrid
ref="grid"
:data="data"
:columns="columns"
:state-persistence="persistenceOptions"
resize-columns
/>
</div>
</template>