getting started

Theming

Learn how to customize the look and feel of the components.

Overview

This module relies on Nuxt App Config file to customize the look and feel of the components at runtime with HMR (hot-module-replacement).

Colors

Configuration

Components are based on a primary and a gray color. You can change them in your app.config.ts.

app.config.ts
export default defineAppConfig({
  ui: {
    primary: 'green',
    gray: 'cool'
  }
})
Try to change the primary and gray colors by clicking on the button in the header.

As this module uses Tailwind CSS under the hood, you can use any of the Tailwind CSS colors or your own custom colors. By default, the primary color is green and the gray color is cool.

CSS Variables

To provide dynamic colors that can be changed at runtime, this module uses CSS variables. As Tailwind CSS already has a gray color, the module automatically renames it to cool to avoid conflicts (coolGray was renamed to gray when Tailwind CSS v3.0 was released).

Likewise, you can't define a primary color in your tailwind.config.ts as it would conflict with the primary color defined by the module.

We'd advise you to use those colors in your components and pages, e.g. text-primary-500 dark:text-primary-400, bg-gray-100 dark:bg-gray-900, etc. so your app automatically adapts when changing your app.config.ts.

The primary color also has a DEFAULT shade that changes based on the theme. It is 500 in light mode and 400 in dark mode. You can use as a shortcut in your components and pages, e.g. text-primary, bg-primary, focus-visible:ring-primary, etc.

Smart Safelisting

Components having a color prop like Avatar, Badge, Button, Input (inherited in Select and SelectMenu), Radio, Checkbox, Toggle, Range and Notification will use the primary color by default but will handle all the colors defined in your tailwind.config.ts or the default Tailwind CSS colors.

Variant classes of those components are defined with a syntax like bg-{color}-500 dark:bg-{color}-400 so they can be used with any color. However, this means that Tailwind will not find those classes and therefore will not generate the corresponding CSS.

The module uses the Tailwind CSS safelist feature to force the generation of all the classes for the primary color only as it is the default color for all the components.

Then, the module will automatically detect when you use one of those components with a color and will safelist it for you. This means that if you use a red color for a Button component, the red color classes will be safelisted for the Button component only. This will allow to keep the CSS bundle size as small as possible.

There is one case where you would want to force the safelisting of a color. For example, if you've set the default color of the Button component to orange in your app.config.ts.

app.config.ts
export default defineAppConfig({
  ui: {
    button: {
      default: {
        color: 'orange'
      }
    }
  }
})

This will apply the orange color when using a default <UButton />. You'll need to safelist this color manually in your nuxt.config.ts ui options as we won't be able to detect it automatically. You can do so through the safelistColors option which defaults to ['primary'].

nuxt.config.ts
export default defineNuxtConfig({
  ui: {
    safelistColors: ['orange']
  }
})

This can also happen when you bind a dynamic color to a component: <UBadge :color="color" />, <UAvatar :chip-color="statuses[user.status]" />, etc. In this case, you'll need to safelist the possible color values manually as well.

Components

app.config.ts

Components are styled with Tailwind CSS but classes are all defined in the default ui.config.ts file. You can override those in your own app.config.ts.

app.config.ts
export default defineAppConfig({
  ui: {
    container: {
      constrained: 'max-w-5xl'
    }
  }
})

Thanks to tailwind-merge, the app.config.ts is smartly merged with the default config. This means you don't have to rewrite everything.

You can change this behaviour by setting strategy to override in your app.config.ts: New

app.config.ts
export default defineAppConfig({
  ui: {
    strategy: 'override',
    button: {
      color: {
        white: {
          solid: 'bg-white dark:bg-gray-900'
        }
      }
    }
  }
})

ui prop

Each component has a ui prop that allows you to customize everything specifically.

<template>
  <UContainer :ui="{ constrained: 'max-w-2xl' }">
    <slot />
  </UContainer>
</template>
You can find the default classes for each component under the Preset section.

Thanks to tailwind-merge, the ui prop is smartly merged with the config. This means you don't have to rewrite everything.

For example, the default preset of the FormGroup component looks like this:

{
  "label": {
    "base": "block font-medium text-gray-700 dark:text-gray-200"
  }
}

To change the font of the label, you only need to write:

<UFormGroup name="email" label="Email" :ui="{ label: { base: 'font-semibold' } }" />

This will smartly replace the font-medium by font-semibold and prevent any class duplication and any class priority issue.

You can change this behaviour by setting strategy to override inside the ui prop: New

<UButton
  to="https://github.com/nuxt/ui"
  :ui="{
    strategy: 'override',
    color: {
      white: {
        solid: 'bg-white dark:bg-gray-900'
      }
    }
  }"
/>

class attribute

You can also use the class attribute to add classes to the component.

<template>
  <UButton label="Button" class="rounded-full" />
</template>

Again, with tailwind-merge, this will smartly merge the classes with the ui prop and the config.

Default values

Some component props like size, color, variant, etc. have a default value that you can override in your app.config.ts.

app.config.ts
export default defineAppConfig({
  ui: {
    button: {
      default: {
        size: 'md',
        color: 'gray',
        variant: 'ghost'
      }
    }
  }
})

Dark mode

All the components are styled with dark mode in mind.

Thanks to Tailwind CSS dark mode class strategy and the @nuxtjs/color-mode module, you literally have nothing to do.

Learn how to build a color mode button in the Examples page.

You can disable dark mode by setting the preference to light instead of system in your nuxt.config.ts.

nuxt.config.ts
export default defineNuxtConfig({
  colorMode: {
    preference: 'light'
  }
})
If you're stuck in dark mode even after changing this setting, you might need to remove the nuxt-color-mode entry from your browser's local storage.

Icons

You can use any icon (100,000+) from Iconify.

Some components have an icon prop that allows you to add an icon to the component.

<template>
  <UButton icon="i-heroicons-magnifying-glass" />
</template>

You can also use the Icon component to add an icon anywhere in your app by following this pattern: i-{collection_name}-{icon_name}.

<template>
  <UIcon name="i-heroicons-moon" />
</template>

By default, the module uses Heroicons but you can change it from the module options in your nuxt.config.ts.

nuxt.config.ts
export default defineNuxtConfig({
  ui: {
    icons: ['mdi', 'simple-icons']
  }
})
Search the icon you want to use on https://icones.js.org built by @antfu.

Unlike the official nuxt-icon module, this module will not fetch any icon from the web and will only bundle the icons you use in your app thanks to egoist/tailwindcss-icons.

However, you will need to install either @iconify/json (full icon collections, 50MB) or the individual icon packages you want to use in your app.

yarn add @iconify-json/{collection_name}

When using @iconify/json, you can specifiy icons: 'all' in your nuxt.config.ts to use any icon in your app.

nuxt.config.ts
export default defineNuxtConfig({
  ui: {
    icons: 'all'
  }
})

You can easily replace all the default icons of the components in your app.config.ts.

app.config.ts
export default defineAppConfig({
  ui: {
    button: {
      default: {
        loadingIcon: 'i-octicon-sync-24'
      }
    },
    input: {
      default: {
        loadingIcon: 'i-octicon-sync-24'
      }
    },
    select: {
      default: {
        loadingIcon: 'i-octicon-sync-24',
        trailingIcon: 'i-octicon-chevron-down-24'
      }
    },
    selectMenu: {
      default: {
        selectedIcon: 'i-octicon-check-24'
      }
    },
    notification: {
      default: {
        closeButton: {
          icon: 'i-octicon-x-24'
        }
      }
    },
    commandPalette: {
      default: {
        icon: 'i-octicon-search-24',
        loadingIcon: 'i-octicon-sync-24',
        selectedIcon: 'i-octicon-check-24',
        emptyState: {
          icon: 'i-octicon-search-24'
        }
      }
    },
    table: {
      default: {
        sortAscIcon: 'i-octicon-sort-asc-24',
        sortDescIcon: 'i-octicon-sort-desc-24',
        sortButton: {
          icon: 'i-octicon-arrow-switch-24'
        },
        loadingState: {
          icon: 'i-octicon-sync-24'
        },
        emptyState: {
          icon: 'i-octicon-database-24'
        }
      }
    },
    pagination: {
      default: {
        prevButton: {
          icon: 'i-octicon-arrow-left-24'
        },
        nextButton: {
          icon: 'i-octicon-arrow-right-24'
        }
      }
    }
  }
})