Theming

Custom Themes

Create custom themes for NuGrid.

Create custom themes to match your application's design.

Creating a Theme

A theme is an object defining CSS classes for each grid element:

// themes/my-theme.ts
import type { NuGridTheme } from '@nu-grid/nuxt/types'

export const myCustomTheme: NuGridTheme = {
  root: 'overflow-auto rounded-lg shadow',
  base: 'w-full border-separate border-spacing-0',
  thead: '[&>tr]:bg-slate-100 dark:[&>tr]:bg-slate-800',
  tbody: '',
  tfoot: 'bg-slate-50 dark:bg-slate-900',
  tr: '',
  th: 'px-4 py-3 text-left font-semibold text-slate-900 dark:text-white',
  td: 'px-4 py-2 border-b border-slate-200 dark:border-slate-700',
  loading: 'opacity-50',
  empty: 'text-center py-8 text-slate-500',
  separator: 'h-4',
}

Theme Properties

PropertyDescription
rootContainer element
baseTable element
theadTable header section
tbodyTable body section
tfootTable footer section
trAll table rows
thHeader cells
tdData cells
loadingApplied when loading
emptyEmpty state container
separatorSeparator between sections

Using Custom Themes

<script setup lang="ts">
import { myCustomTheme } from '~/themes/my-theme'
</script>

<template>
  <NuGrid
    :data="data"
    :columns="columns"
    :theme="myCustomTheme"
  />
</template>

Extending Built-in Themes

Extend the default theme:

import { nuGridTheme } from '@nu-grid/nuxt/themes'

export const myTheme = {
  ...nuGridTheme,
  th: `${nuGridTheme.th} bg-blue-50 dark:bg-blue-900/20`,
  td: `${nuGridTheme.td} hover:bg-blue-50/50`,
}

Or extend the compact theme:

import { nuGridThemeCompact } from '@nu-grid/nuxt/themes'

export const myCompactTheme = {
  ...nuGridThemeCompact,
  thead: '[&>tr]:bg-primary/10',
}

Dynamic Themes

Create themes dynamically:

<script setup lang="ts">
const primaryColor = ref('blue')

const dynamicTheme = computed(() => ({
  root: 'rounded-lg overflow-hidden',
  thead: `[&>tr]:bg-${primaryColor.value}-100 dark:[&>tr]:bg-${primaryColor.value}-900/30`,
  th: `text-${primaryColor.value}-900 dark:text-${primaryColor.value}-100`,
  td: 'border-b border-gray-200 dark:border-gray-700',
}))
</script>

<template>
  <div>
    <USelect
      v-model="primaryColor"
      :items="['blue', 'green', 'purple', 'orange']"
      class="mb-4"
    />

    <NuGrid :data="data" :columns="columns" :theme="dynamicTheme" />
  </div>
</template>

Theme Variants

Create theme variants:

// themes/variants.ts
const baseTheme = {
  root: 'overflow-auto',
  base: 'w-full border-separate border-spacing-0',
  td: 'px-4 py-2',
}

export const lightTheme = {
  ...baseTheme,
  thead: '[&>tr]:bg-gray-100',
  th: 'text-gray-900 font-semibold',
  td: `${baseTheme.td} border-b border-gray-200`,
}

export const darkTheme = {
  ...baseTheme,
  thead: '[&>tr]:bg-gray-800',
  th: 'text-white font-semibold',
  td: `${baseTheme.td} border-b border-gray-700`,
}

export const primaryTheme = {
  ...baseTheme,
  thead: '[&>tr]:bg-primary/20',
  th: 'text-primary font-semibold',
  td: `${baseTheme.td} border-b border-primary/20`,
}

State-Based Styling

Apply styles based on cell/row state:

export const stateAwareTheme = {
  tbody: `
    [&>tr[data-selected=true]]:bg-primary/10
    [&>tr[data-focused=true]]:ring-2
    [&>tr[data-focused=true]]:ring-primary
    [&>tr:hover]:bg-gray-50
    dark:[&>tr:hover]:bg-gray-800/50
  `,
  td: `
    [&[data-editing=true]]:bg-primary/5
    [&[data-invalid=true]]:bg-error/10
  `,
}

Theme with Custom CSS

Use CSS custom properties:

export const cssVarTheme = {
  root: 'grid-theme',
  thead: '[&>tr]:bg-[var(--grid-header-bg)]',
  th: 'text-[var(--grid-header-text)]',
  td: 'border-b border-[var(--grid-border)]',
}
/* app.css */
:root {
  --grid-header-bg: theme('colors.gray.100');
  --grid-header-text: theme('colors.gray.900');
  --grid-border: theme('colors.gray.200');
}

.dark {
  --grid-header-bg: theme('colors.gray.800');
  --grid-header-text: theme('colors.white');
  --grid-border: theme('colors.gray.700');
}

Global Theme Registration

Set a default theme for all grids:

// nuxt.config.ts
export default defineNuxtConfig({
  modules: ['@nu-grid/nuxt'],
  nuGrid: {
    theme: 'custom',  // Use your custom theme as default
  },
})
// plugins/nu-grid.ts
import { myCustomTheme } from '~/themes/my-theme'

export default defineNuxtPlugin((nuxtApp) => {
  nuxtApp.vueApp.provide('nuGridDefaultTheme', myCustomTheme)
})

Example: Complete Custom Theme

// themes/corporate.ts
export const corporateTheme = {
  root: 'rounded-xl overflow-hidden shadow-lg border border-gray-200 dark:border-gray-700',

  base: 'w-full border-separate border-spacing-0',

  thead: `
    [&>tr]:bg-gradient-to-r
    [&>tr]:from-gray-100
    [&>tr]:to-gray-50
    dark:[&>tr]:from-gray-800
    dark:[&>tr]:to-gray-900
  `,

  th: `
    px-4 py-3
    text-left text-sm font-semibold
    text-gray-700 dark:text-gray-200
    first:rounded-tl-xl last:rounded-tr-xl
    border-b-2 border-primary/20
  `,

  tbody: `
    [&>tr]:transition-colors
    [&>tr:hover]:bg-gray-50
    dark:[&>tr:hover]:bg-gray-800/50
    [&>tr:last-child>td]:border-b-0
  `,

  td: `
    px-4 py-3
    text-sm text-gray-600 dark:text-gray-300
    border-b border-gray-100 dark:border-gray-800
    [&[data-focused=true]]:bg-primary/5
    [&[data-focused=true]]:ring-2
    [&[data-focused=true]]:ring-inset
    [&[data-focused=true]]:ring-primary/50
  `,

  loading: 'opacity-60 pointer-events-none',

  empty: `
    text-center py-12
    text-gray-400 dark:text-gray-500
  `,
}

Next Steps

UI Customization

Fine-tune specific grid elements.

Built-in Themes

Explore available themes.