Guide·

Getting Started with Nuxt UI

Build beautiful, accessible interfaces with Nuxt UI's component library.
Getting Started with Nuxt UI
Nuxt UI is a comprehensive Vue component library with 50+ accessible, Tailwind CSS-powered components for building modern web applications.

Why Nuxt UI?

Tailwind CSS Powered

Built on Tailwind CSS with full theming support and CSS variables

Fully Accessible

WCAG compliant components with keyboard navigation and screen reader support

Dark Mode Ready

Seamless light and dark mode switching out of the box

Installation

Add Nuxt UI to your Nuxt project:

npx nuxi@latest module add ui

This automatically adds the module to your nuxt.config.ts:

export default defineNuxtConfig({
  modules: ["@nuxt/ui"],
})

Basic Components

Buttons

Nuxt UI buttons come with multiple variants and colors:

<template>
  <div class="flex gap-2">
    <UButton>Default</UButton>
    <UButton color="primary">Primary</UButton>
    <UButton color="success">Success</UButton>
    <UButton color="error" variant="outline">Error</UButton>
    <UButton color="warning" variant="soft">Warning</UButton>
  </div>
</template>

Inputs

Form inputs with built-in validation states:

<script setup>
  const email = ref("")
</script>

<template>
  <UInput v-model="email" placeholder="Enter your email" icon="i-lucide-mail" />
</template>

Cards

Create beautiful card layouts:

<template>
  <UCard>
    <template #header>
      <h3 class="font-semibold">Card Title</h3>
    </template>

    <p>Card content goes here.</p>

    <template #footer>
      <UButton>Action</UButton>
    </template>
  </UCard>
</template>

Form Handling

Build forms with validation using Nuxt UI's form components:

<script setup lang="ts">
  import { z } from "zod"

  const schema = z.object({
    name: z.string().min(2, "Name must be at least 2 characters"),
    email: z.string().email("Invalid email address"),
  })

  const state = reactive({
    name: "",
    email: "",
  })

  async function onSubmit() {
    console.log("Form submitted:", state)
  }
</script>

<template>
  <UForm :schema="schema" :state="state" @submit="onSubmit">
    <UFormField label="Name" name="name">
      <UInput v-model="state.name" />
    </UFormField>

    <UFormField label="Email" name="email">
      <UInput v-model="state.email" type="email" />
    </UFormField>

    <UButton type="submit">Submit</UButton>
  </UForm>
</template>

Icons

Nuxt UI uses Iconify for icons. Access 200,000+ icons from popular sets:

<template>
  <div class="flex gap-4">
    <!-- Lucide icons (default) -->
    <UIcon name="i-lucide-home" />
    <UIcon name="i-lucide-settings" />

    <!-- Heroicons -->
    <UIcon name="i-heroicons-heart" />

    <!-- Material Design Icons -->
    <UIcon name="i-lucide-github" />

    <!-- Simple Icons (brand logos) -->
    <UIcon name="i-simple-icons-nuxt" />
  </div>
</template>

Use icons in buttons and inputs:

<template>
  <UButton icon="i-lucide-plus">Add Item</UButton>
  <UButton icon="i-lucide-trash" color="error" variant="ghost" />
  <UInput icon="i-lucide-search" placeholder="Search..." />
</template>

Color System

Nuxt UI uses a flexible color system based on Tailwind CSS:

Available Colors

  • primary - Your main brand color
  • secondary - Secondary brand color
  • success - Success states
  • info - Informational states
  • warning - Warning states
  • error - Error states
  • neutral - Neutral/gray tones

Customizing Colors

Configure your colors in app.config.ts:

export default defineAppConfig({
  ui: {
    colors: {
      primary: "blue",
      secondary: "violet",
      success: "emerald",
      error: "red",
    },
  },
})

Dark Mode

Nuxt UI includes built-in dark mode support with the Color Mode module.

Dark Mode Toggle

Create a simple theme toggle:

<script setup>
  const colorMode = useColorMode()

  function toggleDarkMode() {
    colorMode.preference = colorMode.value === "dark" ? "light" : "dark"
  }
</script>

<template>
  <UButton
    :icon="colorMode.value === 'dark' ? 'i-lucide-sun' : 'i-lucide-moon'"
    color="neutral"
    variant="ghost"
    @click="toggleDarkMode"
  />
</template>

Theme Dropdown

Or use a dropdown for more options:

<script setup>
  const colorMode = useColorMode()

  const themes = [
    { label: "Light", value: "light", icon: "i-lucide-sun" },
    { label: "Dark", value: "dark", icon: "i-lucide-moon" },
    { label: "System", value: "system", icon: "i-lucide-monitor" },
  ]
</script>

<template>
  <UDropdownMenu :items="themes">
    <UButton icon="i-lucide-palette" variant="ghost" />
  </UDropdownMenu>
</template>

Build responsive navigation:

<script setup>
  const items = [
    { label: "Home", icon: "i-lucide-home", to: "/" },
    { label: "Products", icon: "i-lucide-box", to: "/products" },
    { label: "About", icon: "i-lucide-info", to: "/about" },
    { label: "Contact", icon: "i-lucide-mail", to: "/contact" },
  ]
</script>

<template>
  <UNavigationMenu :items="items" />
</template>

Show navigation hierarchy:

<script setup>
  const items = [
    { label: "Home", to: "/" },
    { label: "Products", to: "/products" },
    { label: "Laptops", to: "/products/laptops" },
  ]
</script>

<template>
  <UBreadcrumb :items="items" />
</template>

Modals and Overlays

<script setup>
  const isOpen = ref(false)
</script>

<template>
  <UButton @click="isOpen = true">Open Modal</UButton>

  <UModal v-model:open="isOpen">
    <template #header>
      <h3>Modal Title</h3>
    </template>

    <p>Modal content goes here.</p>

    <template #footer>
      <UButton @click="isOpen = false">Close</UButton>
    </template>
  </UModal>
</template>

Toast Notifications

Show feedback messages:

<script setup>
  const toast = useToast()

  function showToast() {
    toast.add({
      title: "Success!",
      description: "Your changes have been saved.",
      color: "success",
    })
  }
</script>

<template>
  <UButton @click="showToast">Show Toast</UButton>
</template>

Data Display

Tables

Display data in tables:

<script setup>
  const columns = [
    { key: "name", label: "Name" },
    { key: "email", label: "Email" },
    { key: "role", label: "Role" },
  ]

  const data = [
    { name: "Alice", email: "alice@example.com", role: "Admin" },
    { name: "Bob", email: "bob@example.com", role: "User" },
  ]
</script>

<template>
  <UTable :columns="columns" :rows="data" />
</template>

Badges

Highlight status or categories:

<template>
  <div class="flex gap-2">
    <UBadge>Default</UBadge>
    <UBadge color="success">Active</UBadge>
    <UBadge color="warning" variant="subtle">Pending</UBadge>
    <UBadge color="error" variant="outline">Inactive</UBadge>
  </div>
</template>

Key Features

50+ Components

From buttons to complex data tables and command palettes

TypeScript First

Full type safety with auto-generated component types

Customizable

Override any component style with Tailwind classes

Explore the full Nuxt UI documentation to discover all available components and features.
Enjoyed this post?
Subscribe to get notified when I publish new articles.

Need a Full Stack Engineer?

10+ years building performant web applications. Let's talk about your next project.