The ui prop provides granular control over NuGrid's appearance, allowing you to customize specific elements without creating a full theme.
<template>
<NuGrid
:data="data"
:columns="columns"
:ui="{
root: 'custom-root-class',
base: 'custom-table-class',
thead: 'custom-thead-class',
tbody: 'custom-tbody-class',
th: 'custom-th-class',
td: 'custom-td-class',
}"
/>
</template>
| Slot | Element | Description |
|---|---|---|
root | Container div | Outermost wrapper |
base | Table element | The table itself |
thead | thead | Table header section |
tbody | tbody | Table body section |
tfoot | tfoot | Table footer section |
tr | tr | All table rows |
th | th | Header cells |
td | td | Data cells |
loading | div | Loading overlay |
empty | div | Empty state message |
separator | tr | Separator rows |
<template>
<NuGrid
:data="data"
:columns="columns"
:ui="{
thead: '[&>tr]:bg-gradient-to-r [&>tr]:from-primary/10 [&>tr]:to-primary/5',
th: 'font-bold text-primary uppercase tracking-wider',
}"
/>
</template>
<template>
<NuGrid
:data="data"
:columns="columns"
:ui="{
td: 'py-4 px-6 text-sm border-b border-gray-100 dark:border-gray-800',
}"
/>
</template>
<template>
<NuGrid
:data="data"
:columns="columns"
:ui="{
tbody: `
[&>tr]:transition-colors
[&>tr:hover]:bg-primary/5
[&>tr:nth-child(even)]:bg-gray-50
dark:[&>tr:nth-child(even)]:bg-gray-800/30
`,
}"
/>
</template>
NuGrid adds data attributes for state-based styling:
| Attribute | Values | Description |
|---|---|---|
data-selected | true/false | Row selection state |
data-focused | true/false | Row focus state |
data-grouped | true/false | Is a group row |
data-expanded | true/false | Group expansion state |
data-add-row | true/false | Is the add-new row |
| Attribute | Values | Description |
|---|---|---|
data-focused | true/false | Cell focus state |
data-editing | true/false | Cell editing state |
data-invalid | true/false | Validation error state |
data-pinned | left/right | Column pinning |
Style based on data attributes:
<template>
<NuGrid
:data="data"
:columns="columns"
:ui="{
tbody: `
[&>tr[data-selected=true]]:bg-primary/10
[&>tr[data-focused=true]]:ring-2
[&>tr[data-focused=true]]:ring-primary
`,
td: `
[&[data-focused=true]]:bg-primary/5
[&[data-editing=true]]:bg-warning/10
[&[data-invalid=true]]:bg-error/10
[&[data-invalid=true]]:ring-1
[&[data-invalid=true]]:ring-error
`,
}"
/>
</template>
Style pinned columns:
<template>
<NuGrid
v-model:column-pinning="columnPinning"
:data="data"
:columns="columns"
:ui="{
th: `
[&[data-pinned=left]]:bg-white
[&[data-pinned=left]]:shadow-[2px_0_5px_-2px_rgba(0,0,0,0.1)]
dark:[&[data-pinned=left]]:bg-gray-900
[&[data-pinned=right]]:bg-white
[&[data-pinned=right]]:shadow-[-2px_0_5px_-2px_rgba(0,0,0,0.1)]
dark:[&[data-pinned=right]]:bg-gray-900
`,
td: `
[&[data-pinned=left]]:bg-white
dark:[&[data-pinned=left]]:bg-gray-900
[&[data-pinned=right]]:bg-white
dark:[&[data-pinned=right]]:bg-gray-900
`,
}"
/>
</template>
Style grouped rows:
<template>
<NuGrid
v-model:grouping="grouping"
:data="data"
:columns="columns"
:ui="{
tbody: `
[&>tr[data-grouped=true]]:bg-gray-100
dark:[&>tr[data-grouped=true]]:bg-gray-800
[&>tr[data-grouped=true]]:font-semibold
`,
}"
/>
</template>
Style the add-new row:
<template>
<NuGrid
:data="data"
:columns="columns"
:add-new-row="true"
:ui="{
tbody: `
[&>tr[data-add-row=true]]:bg-success/5
[&>tr[data-add-row=true]]:border-dashed
[&>tr[data-add-row=true]]:border-success/30
`,
}"
/>
</template>
Style the loading state:
<template>
<NuGrid
:data="data"
:columns="columns"
:loading="isLoading"
:ui="{
loading: 'absolute inset-0 bg-white/50 dark:bg-gray-900/50 backdrop-blur-sm flex items-center justify-center',
}"
/>
</template>
Style the empty state:
<template>
<NuGrid
:data="data"
:columns="columns"
:ui="{
empty: 'py-16 text-center text-gray-400',
}"
>
<template #empty>
<div class="flex flex-col items-center gap-2">
<UIcon name="i-lucide-inbox" class="size-12 text-gray-300" />
<p class="text-lg font-medium">No data available</p>
<p class="text-sm">Add some items to get started.</p>
</div>
</template>
</NuGrid>
</template>
The ui prop is merged with the theme:
<script setup lang="ts">
import { nuGridThemeCompact } from '@nu-grid/nuxt/themes'
</script>
<template>
<NuGrid
:data="data"
:columns="columns"
:theme="nuGridThemeCompact"
:ui="{
thead: '[&>tr]:bg-primary/10', <!-- Added to compact theme -->
}"
/>
</template>
<template>
<NuGrid
v-model:row-selection="rowSelection"
:data="data"
:columns="columns"
selection="multi"
:editing="{ enabled: true }"
:ui="{
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-slate-100
[&>tr]:to-slate-50
dark:[&>tr]:from-slate-800
dark:[&>tr]:to-slate-900
`,
th: `
px-4 py-3
text-left text-xs font-bold uppercase tracking-wider
text-slate-600 dark:text-slate-300
first:rounded-tl-xl last:rounded-tr-xl
`,
tbody: `
[&>tr]:transition-all [&>tr]:duration-150
[&>tr:hover]:bg-slate-50 dark:[&>tr:hover]:bg-slate-800/50
[&>tr[data-selected=true]]:bg-primary/10
[&>tr:last-child>td]:border-b-0
[&>tr:last-child>td:first-child]:rounded-bl-xl
[&>tr:last-child>td:last-child]:rounded-br-xl
`,
td: `
px-4 py-3
text-sm text-slate-700 dark:text-slate-300
border-b border-slate-100 dark:border-slate-800
[&[data-focused=true]]:ring-2
[&[data-focused=true]]:ring-inset
[&[data-focused=true]]:ring-primary/50
[&[data-editing=true]]:bg-primary/5
`,
empty: 'py-12 text-center text-slate-400',
}"
/>
</template>