Advanced

State Persistence

Save and restore NuGrid state across sessions.

NuGrid can automatically persist and restore grid state, including column sizes, sorting, filters, and more.

Enabling Persistence

Enable state persistence with the state-persistence prop:

<template>
  <NuGrid
    :data="data"
    :columns="columns"
    :state-persistence="{
      key: 'my-grid',
      storage: 'local',
    }"
  />
</template>

Persistence Options

interface StatePersistenceOptions {
  key: string
  storage: 'local' | 'session' | 'custom'
  include?: string[]
  exclude?: string[]
  debounce?: number
  onSave?: (state: any) => void
  onLoad?: (state: any) => any
}

Options Reference

OptionTypeDefaultDescription
keystringrequiredStorage key
storage'local' | 'session' | 'custom''local'Storage type
includestring[]All stateState keys to persist
excludestring[]NoneState keys to exclude
debouncenumber300Debounce delay (ms)
onSavefunction-Called before saving
onLoadfunction-Called after loading

Persisted State

By default, the following state is persisted:

  • Column sizing
  • Column ordering
  • Column visibility
  • Column pinning
  • Sorting
  • Filters
  • Expanded rows (grouping)
  • Pagination

Selective Persistence

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>

Storage Types

Local Storage

Persists across browser sessions:

<template>
  <NuGrid
    :data="data"
    :columns="columns"
    :state-persistence="{
      key: 'my-grid',
      storage: 'local',
    }"
  />
</template>

Session Storage

Persists only for the current session:

<template>
  <NuGrid
    :data="data"
    :columns="columns"
    :state-persistence="{
      key: 'my-grid',
      storage: 'session',
    }"
  />
</template>

Custom Storage

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>

Transform State

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>

Manual State Management

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>

Reset State

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>

Per-User State

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>

Example: Complete Persistence Setup

<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>

Next Steps

Drag & Drop

Enable row and column reordering.

Events

Handle grid events.