Stat Group

GitHub
A responsive grid container for displaying stat cards and other stat components.

Usage

The StatGroup component provides a responsive grid layout for displaying stat cards and other stat components.

Users
12,345
+12.5%
Sales
$45,231
+8.2%
Revenue
$125,430
Sessions
1,234
+15.3%
<script setup lang="ts">
const items = [
  { icon: 'i-lucide-users', title: 'Users', value: '12,345', trend: 12.5, trendDirection: 'up' as const },
  { icon: 'i-lucide-shopping-cart', title: 'Sales', value: '$45,231', trend: 8.2, trendDirection: 'down' as const },
  { icon: 'i-lucide-dollar-sign', title: 'Revenue', value: '$125,430' },
  { icon: 'i-lucide-activity', title: 'Sessions', value: '1,234', trend: 15.3, trendDirection: 'up' as const }
]
</script>

<template>
  <UStatGroup :cols="4">
    <UStatCard
      v-for="item in items"
      :key="item.title"
      :icon="item.icon"
      :title="item.title"
      :value="item.value"
      :trend="item.trend"
      :trend-direction="item.trendDirection"
    />
  </UStatGroup>
</template>

Columns

Use the cols prop to control the number of columns. The grid is responsive and adapts to screen size.

Users
12,345
Sales
$45,231
<script setup lang="ts">
const items = [
  { icon: 'i-lucide-users', title: 'Users', value: '12,345' },
  { icon: 'i-lucide-shopping-cart', title: 'Sales', value: '$45,231' }
]
</script>

<template>
  <UStatGroup :cols="2">
    <UStatCard
      v-for="item in items"
      :key="item.title"
      :icon="item.icon"
      :title="item.title"
      :value="item.value"
    />
  </UStatGroup>
</template>

Gap

Use the gap prop to control the spacing between grid items.

Users
12,345
Sales
$45,231
<script setup lang="ts">
const items = [
  { icon: 'i-lucide-users', title: 'Users', value: '12,345' },
  { icon: 'i-lucide-shopping-cart', title: 'Sales', value: '$45,231' }
]
</script>

<template>
  <UStatGroup :cols="2" gap="lg">
    <UStatCard
      v-for="item in items"
      :key="item.title"
      :icon="item.icon"
      :title="item.title"
      :value="item.value"
    />
  </UStatGroup>
</template>

Title and Actions

Use the title prop and actions slot to add a header with title and action buttons.

Dashboard Overview
Users
12,345
Sales
$45,231
<script setup lang="ts">
const items = [
  { icon: 'i-lucide-users', title: 'Users', value: '12,345' },
  { icon: 'i-lucide-shopping-cart', title: 'Sales', value: '$45,231' }
]
</script>

<template>
  <UStatGroup title="Dashboard Overview" :cols="2">
    <template #actions>
      <UButton size="xs" variant="ghost">
        Last 30 days
      </UButton>
    </template>
    <UStatCard
      v-for="item in items"
      :key="item.title"
      :icon="item.icon"
      :title="item.title"
      :value="item.value"
    />
  </UStatGroup>
</template>

API

Props

Prop Default Type
as'section'any

The element or component this component should render as.

cols4 4 | 1 | 2 | 3

Number of columns in the grid layout.

gap'md' "md" | "xs" | "sm" | "lg" | "xl"

Gap between grid items.

title string

Optional title for the group.

ui { root?: ClassNameValue; header?: ClassNameValue; title?: ClassNameValue; actions?: ClassNameValue; grid?: ClassNameValue; }

Slots

Slot Type
header{ ui: object; }
title{ title?: string | undefined; ui: object; }
actions{ ui: object; }
default{ ui: object; }

Theme

app.config.ts
export default defineAppConfig({
  ui: {
    statGroup: {
      slots: {
        root: 'flex flex-col',
        header: 'flex items-center justify-between gap-4 mb-4',
        title: 'text-lg font-semibold text-highlighted',
        actions: 'flex items-center gap-2',
        grid: 'grid w-full'
      },
      variants: {
        gap: {
          xs: {
            grid: 'gap-2'
          },
          sm: {
            grid: 'gap-3'
          },
          md: {
            grid: 'gap-4'
          },
          lg: {
            grid: 'gap-6'
          },
          xl: {
            grid: 'gap-8'
          }
        },
        cols: {
          '1': {
            grid: 'grid-cols-1'
          },
          '2': {
            grid: 'grid-cols-1 sm:grid-cols-2'
          },
          '3': {
            grid: 'grid-cols-1 sm:grid-cols-2 lg:grid-cols-3'
          },
          '4': {
            grid: 'grid-cols-1 sm:grid-cols-2 lg:grid-cols-4'
          }
        }
      },
      defaultVariants: {
        gap: 'md',
        cols: 4
      }
    }
  }
})
vite.config.ts
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import ui from '@nuxt/ui/vite'

export default defineConfig({
  plugins: [
    vue(),
    ui({
      ui: {
        statGroup: {
          slots: {
            root: 'flex flex-col',
            header: 'flex items-center justify-between gap-4 mb-4',
            title: 'text-lg font-semibold text-highlighted',
            actions: 'flex items-center gap-2',
            grid: 'grid w-full'
          },
          variants: {
            gap: {
              xs: {
                grid: 'gap-2'
              },
              sm: {
                grid: 'gap-3'
              },
              md: {
                grid: 'gap-4'
              },
              lg: {
                grid: 'gap-6'
              },
              xl: {
                grid: 'gap-8'
              }
            },
            cols: {
              '1': {
                grid: 'grid-cols-1'
              },
              '2': {
                grid: 'grid-cols-1 sm:grid-cols-2'
              },
              '3': {
                grid: 'grid-cols-1 sm:grid-cols-2 lg:grid-cols-3'
              },
              '4': {
                grid: 'grid-cols-1 sm:grid-cols-2 lg:grid-cols-4'
              }
            }
          },
          defaultVariants: {
            gap: 'md',
            cols: 4
          }
        }
      }
    })
  ]
})

Changelog

No recent changes