Skip to content

Releases: nuxt/ui

v4.9.0

17 Jun 14:18
v4.9.0
2166ff7

Choose a tag to compare

✨ Highlights

📆 Calendar month and year selection

The Calendar component gains a single type prop (date | month | year, default date) that renders it as a day, month or year picker, covering both standalone pickers and quick navigation:

<script setup lang="ts">
const value = shallowRef(new CalendarDate(2026, 6, 17))
</script>

<template>
  <UCalendar v-model="value" type="month" />
</template>

Tip

In date mode the heading also becomes a clickable button that cycles day → month → year, so you can jump to a month or year without clicking through prev / next repeatedly. This is controlled by the new viewControls and viewButton props and works with range.

🧭 useTour composable

The new useTour composable drives guided tours by re-anchoring a single Popover across steps. It owns the step state and resolves each step's target into a reference you bind to <UPopover>, while you keep full control over the content and navigation:

<script setup lang="ts">
const card = useTemplateRef('card')

const tour = useTour([
  { target: '#cta', title: 'Get started' },
  { target: () => card.value, title: 'Profile', side: 'right' },
  { target: null, title: 'All set' }
])
</script>

<template>
  <UButton @click="tour.start()">Start tour</UButton>

  <UPopover :open="tour.open.value" :reference="tour.reference.value" :dismissible="false">
    <template #content>
      <!-- your content + buttons -->
      <UButton :disabled="!tour.hasPrev.value" @click="tour.prev()">Back</UButton>
      <UButton @click="tour.next()">{{ tour.hasNext.value ? 'Next' : 'Finish' }}</UButton>
    </template>
  </UPopover>
</template>

✂️ Override default classes

A new build-time theme.unstyled option strips Nuxt UI's default theme classes from every component, keeping only their structure and the classes you provide through class, ui or app.config.ui. This lets you bring your own design system on top of the components' logic and accessibility, or cut HTML and bundle bloat:

export default defineNuxtConfig({
  modules: ['@nuxt/ui'],
  css: ['~/assets/css/main.css'],
  ui: {
    theme: {
      unstyled: true
    }
  }
})

Warning

This strips structural classes too (positioning, transitions, flex/grid), not just cosmetic ones. Layout-heavy components like Modal, Drawer or Calendar will need you to re-supply their layout.

For more surgical control, slot classes can now be a (defaults) => classes function that replaces the slot's defaults instead of merging onto them. It receives the resolved defaults so you can reuse part of them, while plain strings keep merging exactly as before. It works in :ui, app.config.ui and <UTheme :ui>:

<template>
  <UButton :ui="{ base: () => 'text-3xl font-bold' }" label="Button" />
</template>

🎯 Uniform focus styles

Every component now shares a single focus-visible language: a soft outline halo tinted with the component's color (e.g. outline-primary/25), so the indicator stays consistent and accessible across every variant and color. Tab panels, scrollable regions and overlay links that browsers make focusable now show the halo too, instead of hiding focus entirely.

If you prefer one outline color across your whole app regardless of component color, a single global rule in your main.css does it:

*,
::before,
::after {
  @apply outline-primary/25;
}

*:focus-visible,
*:has(> a:focus-visible) {
  --tw-ring-color: var(--ui-primary);
}

Note

Check out the before/after preview images in #6576.

🚀 Features

🐛 Bug Fixes

  • CommandPalette: only scroll to highlighted item when focused (#6579) (02259a6)
  • Link: set default for locale prop (#6563) (e9ab758)
  • module: remove inline script in SPA mode for strict CSP (#6577) (7225e9f)
  • ProseCodeCollapse: cap root max-height instead of toggling pre height (#6565) (52d3c45)
  • ProseKbd: type default slot as VNode[] (52367b1)
  • SelectMenu: bind id and aria attributes on trigger (#6572) (c3bef7a)
  • Select: open menu on label click (#6575) (e8d18c3)
  • Tabs: render active indicator during SSR (#6570) (9e5b8a6)
  • templates: resolve vite root to an absolute path for #build aliases (#6586) (238e291)

🌐 Locales

❤️ Contributors

Full Changelog: v4.8.2...v4.9.0

v4.8.2

04 Jun 14:48
v4.8.2
d6341d5

Choose a tag to compare

🐛 Bug Fixes

  • Form: support setting the name attribute (#6539) (f8186e2)
  • InputMenu/SelectMenu: re-highlight first item when items change (#6538) (0414dd0)
  • InputNumber/InputDate/InputTime/Calendar: restore locale prop (#6546) (ed2f955)
  • module: merge custom variants into AppConfig type (#6531) (f0571c3)

Full Changelog: v4.8.1...v4.8.2

v4.8.1

28 May 15:36
v4.8.1
00aded7

Choose a tag to compare

🐛 Bug Fixes

  • ContentSearch/DashboardSearch: proxy missing CommandPalette props (#6505) (631f5dc)
  • Form: add method="post" to prevent credential leaking via GET before hydration (#6512) (7a0825a)
  • Icon: avoid recursive icon resolution (#6495) (d50c121)
  • locale: improve Thai translation accuracy and consistency (#6509) (5d82418)
  • module: expose component theme keys in AppConfig type (#6520) (ffaf163)
  • Select/SelectMenu/InputMenu: add fallback for max-height (#6503) (f4d7cbe)

👋 Contributors

Full Changelog: v4.8.0...v4.8.1

v4.8.0

21 May 15:03
v4.8.0
24b23fd

Choose a tag to compare

✨ Highlights

🎨 Theme component prop defaults

The Theme component can now override default prop values for all descendant components. Pass a props object where keys are component names and values are their prop overrides:

<template>
  <UTheme
    :props="{
      tooltip: { delayDuration: 0, arrow: true },
      button: { color: 'neutral', variant: 'subtle', size: 'lg' },
      input: { size: 'lg' }
    }"
  >
    <UTooltip text="Tooltip">
      <UButton label="Save" />
    </UTooltip>

    <UInput placeholder="Search..." />
  </UTheme>
</template>

Explicit props on a component always take priority. Theme components can be nested (innermost wins) and propagate through the entire tree via provide / inject.

🔍 ContentSearch async search

The ContentSearch component now supports FTS5 full-text search via the new search prop and the useSearchCollection composable (nuxt/content#3787, released in @nuxt/content v3.14.0). Instead of loading all content upfront with files and filtering client-side with Fuse.js, you can now run async queries with highlighted snippets:

<script setup lang="ts">
const { search, status, init } = useSearchCollection('content', {
  immediate: false,
  ignoredTags: ['style']
})

const { open } = useContentSearch()

watch(open, (value) => {
  if (value && status.value === 'idle') {
    init()
  }
})
</script>

<template>
  <UContentSearch :search="search" :search-status="status" />
</template>

You can check out the new search on https://ui.nuxt.com or https://nuxt.com.

🚨 Breaking Changes

  • InputMenu: rename autocomplete prop to mode to free up HTML attribute (#6474)

The boolean autocomplete prop introduced in v4.6.0 collided with the standard HTML autocomplete attribute used for browser autofill (address-line1, one-time-code, email, etc.). It has been renamed to mode which accepts 'combobox' | 'autocomplete' (defaults to combobox). The HTML autocomplete attribute now falls through to the inner input like other form components.

- <UInputMenu autocomplete :items="items" />
+ <UInputMenu mode="autocomplete" :items="items" />

🚀 Features

  • Avatar/AvatarGroup: add color prop (#6405) (6f2396f)
  • Breadcrumb: add color prop (#6406) (955dac1)
  • ChatMessage: add body slot and improve actions alignment (#6460) (48685b6)
  • ChatMessage: add color prop and header slot (#6407) (c6ce8ca)
  • ChatPrompt: add submitOnEnter prop to control Enter behavior (b597f90)
  • Checkbox/RadioGroup/Switch: add highlight prop for error ring styling (a0deee4)
  • CommandPalette: search and highlight description field (524c34d)
  • ContentSearch/DashboardSearch: enable Fuse.js token search by default (ba08220)
  • ContentSearch: add async search support via useSearchCollection (#6432) (a1bef8b)
  • DashboardGroup: add storageOptions prop (8f0101b)
  • Error: add icon prop and leading slot (e6ea707)
  • Separator: add position prop (#6415) (844660a)
  • Theme: override component prop defaults (#6031) (71c008e)

🐛 Bug Fixes

  • ChatMessage: add wrap-break-word to content slot (#6476) (eb468e6)
  • CommandPalette: only split tokens in highlight when useTokenSearch is enabled (898fbce)
  • CommandPalette: preserve relative order of ignoreFilter groups (e4c1787)
  • CommandPalette: re-highlight first item after debounced results render (efd7b8e)
  • CommandPalette: update default fuse keys in docs and search components (0d9cc0d)
  • components: apply theme.prefix to hardcoded utility classes (f51b1e8)
  • components: constrain popper content to available viewport height (007b136)
  • ContentSearch: preserve intermediate ancestors in breadcrumb prefix (#6466) (f639b19)
  • ContentToc: apply ui.trigger prop to trigger elements (252b906)
  • defineShortcuts: use e.code for alt shortcuts to handle macOS key remapping (231f156)
  • FileUpload: pass disabled attribute to button variant (2890c83)
  • Form: improve errors type (#6208) (c1090ab)
  • InputMenu/Select/SelectMenu: respect trailing: false over default trailingIcon (#6457) (65b47ce)
  • InputMenu: rename autocomplete prop to mode to free up HTML attribute (#6474) (2799fa6)
  • module: don't require @nuxtjs/mdc when using content option (89f7778)
  • module: pass computed ref directly to useHead innerHTML (00b7476)
  • module: ship stripped #build/ui.css fallback for tooling (083c2a9)
  • ProseKbd: add default slot and make value optional (f317c7f)
  • Textarea: autoresize on mount with pre-filled value (e96a0b6)
  • useComponentProps: treat array-typed theme values as ClassValue leaves (cac3860)

👋 Contributors

Full Changelog: v4.7.1...v4.8.0

v4.7.1

28 Apr 13:42
v4.7.1
4587079

Choose a tag to compare

🐛 Bug Fixes

  • ChatMessage: make actions slot accessible on touch devices (f5a3349)
  • Drawer: handle RTL mode (#6396) (2e3fed2)
  • Link: prevent double-prefixing with @nuxtjs/i18n auto-localization (#6404) (dde09d0)
  • ProseImg: close zoom overlay on Escape key (e3cdbc5)
  • ProsePrompt: improve responsive (0a5b433)

👋 New Contributors

Full Changelog: v4.7.0...v4.7.1

v4.7.0

24 Apr 15:07
v4.7.0
0cfb606

Choose a tag to compare

✨ Highlights

📋 New Listbox component

The Listbox component is a selectable list of items with built-in search, virtualization, and rich item rendering. It's ideal when you want an always-visible list without the overlay behavior of SelectMenu.

<script setup lang="ts">
const items = ref([
  { label: 'France', icon: 'i-lucide-map-pin', value: 'FR' },
  { label: 'Germany', icon: 'i-lucide-map-pin', value: 'DE' },
  { label: 'Italy', icon: 'i-lucide-map-pin', value: 'IT' },
  { label: 'Spain', icon: 'i-lucide-map-pin', value: 'ES' }
])

const value = ref()
</script>

<template>
  <UListbox v-model="value" :items="items" />
</template>

🤖 New ProsePrompt component

The ProsePrompt component displays pre-built AI prompts inside your docs with one-click copy and direct IDE integration. Users can copy the prompt to their clipboard or open it directly in Cursor or Windsurf via the actions prop.

::prompt
---
description: Build a dashboard layout with Nuxt UI.
icon: i-lucide-layout-dashboard
actions:
  - copy
  - cursor
  - windsurf
---
You are a Nuxt UI expert. Help me build a dashboard layout with
a collapsible sidebar and a sticky top navbar.
::

🌍 Automatic Link localization

The Link component now integrates automatically with @nuxtjs/i18n when installed. Internal links are localized using the $localePath helper under the hood (#5537).

<template>
  <!-- Automatically becomes /en/about or /fr/about based on current locale -->
  <ULink to="/about">About</ULink>
</template>

This also propagates to every component that accepts a to prop (NavigationMenu, Breadcrumb, DropdownMenu, CommandPalette, etc.), so routes stay locale-aware across your entire app.

🚀 Features

  • AuthForm: add separator slot (#6305) (81c7ddb)
  • Card: add title and description props (3cf7d75), closes #6001
  • CommandPalette: add group-label slot (#6329) (7fc773c)
  • CommandPalette: add searchDelay prop (7d2af05)
  • EditorSuggestionMenu: expose suggestion matching options (#6234) (4427824)
  • Link: auto-localize internal links when @nuxtjs/i18n is installed (#5537) (92cfda0)
  • Listbox: new component (#6307) (00c1651)
  • ProsePrompt: new component (#6362) (2451ac6)
  • Table: support sticky header/footer in virtualized mode (#6217) (15d32ce)
  • Textarea: expose autoResize method (#6120) (9c5c0df)

🐛 Bug Fixes

  • Accordion/Tabs: use item value as stable key to avoid remounts (#6380) (3cee610)
  • Avatar: remove leading-none from fallback (#6383) (77ce09a)
  • ChatMessage/ChatMessages: preserve generic message type in slot scope (#6391) (20f66db)
  • ChatMessages: prevent layout shift caused by indicator during streaming (#6297) (b7160e2)
  • ChatMessages: use MutationObserver for auto-scroll during streaming (#6357) (47bf3cb)
  • ChatPromptSubmit: ignore disabled prop when status is not ready (600a2ca)
  • components: resolve defaultVariants in template logic (#6361) (75b37d0)
  • ContentSearch/DashboardSearch: pick shared props from CommandPalette (cdcf2e5)
  • ContentSearch: speed up navigation mapping (0faf2c2)
  • ContentToc: use links for scrollspy instead of hardcoded h2/h3 (#6282) (6aba2ea)
  • FieldGroup: prevent context from leaking into portals (#6313) (5155e27)
  • FileUpload: use form field color and highlight instead of raw props (bb5a9ed)
  • Header/DashboardSidebar/Sidebar: allow auto focus in menu for proper focus trapping (#6266) (9b91ee4)
  • InputDate/InputTime: increase segments width (#6339) (4ebdb2f)
  • InputTags: add missing field group variant (#6326) (aae5378)
  • Link: ensure single-root rendering for v-show and $el resolution (#6310) (2c4ff35)
  • Modal/Slideover: drop empty header wrapper when empty (#6381) (1082960)
  • module: use relative tagPriority for inline style tags (#6299) (ae693d0)
  • PricingTable: align header elements vertically (#6111) (0daacb0)
  • PricingTable: handle RTL mode (#6382) (ab203db)
  • ProseCodeCollapse: match background on overscroll (28c89fe)
  • ProseImg: respect markdown width attribute (#6350) (d4e4ea1)
  • ProsePre: get code from DOM if code prop is missing (#6333) (b808ce4)
  • Select: support item-aligned position mode (#6358) (255807a)

👋 New Contributors

Full Changelog: v4.6.1...v4.7.0

v4.6.1

03 Apr 15:11
v4.6.1
08be59c

Choose a tag to compare

🐛 Bug Fixes

  • ai: use part.state for streaming detection and deprecate isReasoningStreaming (d2d7543)
  • ChatMessage: hide files slot when no file parts exist (9cddc8e)
  • ChatMessages: keep indicator visible until first content arrives (195cce8)
  • ChatMessages: reset scroll icon when messages are cleared (#6239) (4ba3eef)
  • ChatPrompt: guard enter during composition (#6280) (a911ca8)
  • DashboardSidebar: always pass collapsed: false in mobile menu slots (957a0f5), closes #6157
  • Modal/Slideover/Drawer: suppress reka ui title and description warnings (3451b8d), closes #6240
  • module: inline defaultVariants and prefix in dev template (314e23b)
  • module: transpile reka-ui to prevent injection errors (#6286) (b822c43)

New Contributors

Full Changelog: v4.6.0...v4.6.1

v4.6.0

23 Mar 15:56
v4.6.0
4cac349

Choose a tag to compare

✨ Highlights

📁 New Sidebar component

The Sidebar component provides a responsive application sidebar that stays fixed on desktop and transforms into a Modal, Slideover, or Drawer on mobile. It supports three visual variants (sidebar, floating, inset) and three collapsible modes (offcanvas, icon, none):

<template>
  <USidebar v-model:open="open" collapsible="icon">
    <template #header>
      <Logo />
    </template>

    <UNavigationMenu :items="items" />

    <template #footer>
      <UserMenu />
    </template>
  </USidebar>
</template>

🤖 New Chat components

We're introducing 3 new components to build richer AI chat interfaces:

  • ChatReasoning: A collapsible thinking/reasoning block that automatically tracks streaming duration.
  • ChatTool: A collapsible row for tool invocations with loading and streaming states.
  • ChatShimmer: An animated text primitive used internally by ChatReasoning and ChatTool during streaming.

These components integrate seamlessly with the AI SDK message parts:

<template>
  <UChatMessages :messages="messages" :status="status">
    <template #content="{ message }">
      <template v-for="(part, index) in message.parts" :key="index">
        <UChatReasoning
          v-if="isReasoningUIPart(part)"
          :text="part.reasoning"
          :streaming="isReasoningStreaming(message, index, chat)"
        />
        <UChatTool
          v-else-if="isToolInvocationUIPart(part)"
          :text="part.toolInvocation.toolName"
          :streaming="isToolStreaming(part)"
        />
        <MDC v-else-if="isTextUIPart(part)" :value="part.text" />
      </template>
    </template>
  </UChatMessages>
</template>

🚨 Breaking Changes

  • module: use moduleDependencies to manipulate options (#5384)

This release adopts Nuxt's new moduleDependencies API to declaratively manage sub-module dependencies (@nuxt/icon, @nuxt/fonts, @nuxtjs/color-mode, @nuxtjs/mdc) instead of manually installing them at runtime. This requires Nuxt >= 4.1.0.

🚀 Features

🐛 Bug Fixes

  • Avatar: use resolved size for image width/height (#6008) (6dd0fc4)
  • ContentNavigation: prevent toggling disabled parent items (#6122) (0f1074f)
  • ContentSurround: handle RTL mode (#6148) (6921f13)
  • ContentToc: reset start margin at lg breakpoint (8f24f79)
  • DashboardSearchButton: use valid HTML structure for trailing slot (#6194) (578a12f)
  • Editor: guard lift calls for unavailable list extensions (#6100) (065db6b)
  • Error: support status and statusText properties (1350d62), closes #6134
  • FileUpload: make multiple, accept and reset options reactive (#6204) (ae093df)
  • Modal/Slideover/Popover/Drawer: prevent double close:prevent emit (#6226) (9a0d501)
  • module: only auto-import public composables and allow Vite opt-out (#6197) (886f5fb)
  • NavigationMenu: improve RTL support for viewport and indicator (#6164) (755867b)
  • NavigationMenu: propagate disabled state to item in vertical orientation (6d4d651)
  • ProsePre: move shiki line highlight styles to theme (d663950)

🌐 Locales

👋 New Contributors

Full Changelog: v4.5.1...v4.6.0

v4.5.1

02 Mar 16:31
v4.5.1
6f3a255

Choose a tag to compare

🐛 Bug Fixes

  • components: improve arrow styling with stroke-default and fill-bg (#6095) (0e9198e)
  • components: improve slots return types and tests (#6109) (7d1e863)
  • components: prevent transformUI from mutating cached useComponentUI value (286738a), closes #6104 #4387
  • ContentToc: add relative positioning to content slot (fcdb231), closes #6117
  • ContentToc: use rem units for indicator size calculation (d631853)
  • NavigationMenu: prevent navigation when clicking trailing area in horizontal orientation (8f84c90), closes #6083
  • Page: make slot presence reactive for variant computation (082ea41)
  • types: resolve isArrayOfArray type return (#6097) (04292d9)
  • useResizable: use function declaration to prevent false auto-import (c22ecf4)

👋 New Contributors

Full Changelog: v4.5.0...v4.5.1

v4.5.0

24 Feb 13:22
v4.5.0
3fa54f5

Choose a tag to compare

✨ Highlights

🎨 New Theme component

The Theme component lets you override the theme of all child components without modifying each one individually. Pass an object to the ui prop where keys are component names and values are their slot class overrides:

<UTheme
  :ui="{
    button: {
      base: 'rounded-full'
    },
    input: {
      base: 'rounded-full'
    }
  }"
>
  <UButton label="Button" color="neutral" variant="outline" />
  <UInput placeholder="Search..." />
</UTheme>

The Theme component doesn't render any HTML element. It uses Vue's provide / inject under the hood, so overrides propagate through the entire component tree regardless of nesting depth. Theme components can be nested (innermost wins) and the ui prop on individual components always takes priority.

🌈 New neutral colors

Thanks to Tailwind CSS v4.2, four new neutral color options are now available: taupe, mauve, mist and olive. Configure them through the ui.neutral option in your app.config.ts.

🚫 Duplicate toast prevention

The Toaster now automatically prevents duplicate toasts and displays a pulse animation when a duplicate is triggered, providing a cleaner notification experience: https://ui.nuxt.com/docs/components/toast#deduplicated-toasts

1oUPxZsXIbjXRiJt.mp4

🚀 Features

  • DashboardSidebar/Header: add autoClose prop (#6089) (2663deb)
  • EditorDragHandle: proxy nested / nestedOptions props and emit hover event (#5960) (ed60193)
  • Form: add HTML5 validation to programmatic submit (#6002) (ed552fc)
  • module: add support for taupe / mauve / mist / olive neutral colors (#6081) (bc49d3f)
  • NavigationMenu: allow tooltip usage in horizontal orientation (#5682) (f46b504)
  • NavigationMenu: handle chip in items (#6064) (401a2c0)
  • ScrollArea: add skipMeasurement virtualize option (#5721) (548b711)
  • Select/SelectMenu: add hover effects on outline and subtle variants (94b0c31)
  • Theme: new component (#4387) (c97047d)
  • Toaster: prevent duplicate toasts and add pulse animation (3f6581a)

🐛 Bug Fixes

  • BlogPost/ChangelogVersion: use ImgHTMLAttributes type for image prop (#6007) (0185856)
  • ChatMessages: allow message props to override role defaults (#6000) (f64ec17)
  • ChatMessages: prevent flash at top before scrolling to bottom on mount (4bdcb83)
  • Checkbox/Switch: prevent data-state conflict when used inside Tooltip (2bb1a8b), closes #3599
  • CheckboxGroup: update update:modelValue emit type (#5927) (64d2e88)
  • ColorModeImage: add baseURL support for public paths (#6006) (db510f3)
  • components: add fixed prop to prevent responsive text size reduction (#6074) (8f5f44c)
  • components: nullable and optional type support (#6060) (cd3432b)
  • components: prevent iOS auto-zoom on input fields with font-size below 16px (#6040) (1262016)
  • ContentNavigation: pass nested child data to slots (#6043) (e67f77e)
  • defineShortcuts: add alt key guard (#6020) (8451f45)
  • defineShortcuts: allow shifted special character shortcuts (08facc0)
  • Drawer/Modal/Popover/Slideover: prevent unexpected close on touch when interacting with other overlays (#5695) (e2c038c)
  • Editor: handle placeholder in RTL mode (#5977) (3cc16e3)
  • EditorMentionMenu: use char prop as mention prefix instead of always @ (0b9b097), closes #6035
  • EditorToolbar: proxy size prop to dropdown menu (8f8d989)
  • InputMenu/InputNumber/SelectMenu: proxy size to buttons (1ec1698), closes #5958
  • InputMenu/Select/SelectMenu: exclude cosmetic items from model value type (#6044) (22cf1ea)
  • InputMenu/SelectMenu: sort filtered items by match relevance (058c66b), closes #4672
  • InputMenu: prevent focus on trailing button (88073b6)
  • module: update icon cssLayer option from components to base (#6076) (e8bc322)
  • NavigationMenu: allow clicking trailing slot in horizontal orientation (7f9996f), closes #5192 #6083
  • NavigationMenu: unique auto-generated item values for grouped items (7b317d9)
  • PricingPlan: truncate title (#6041) (8e86c51)
  • Select: remove useless by prop (14dceaf)
  • Table: improve perfs with shallowRef when watch deep is disabled (#6023) (bc06ce2)
  • Toast: allow update to keep toast open and reset duration (82afa0a)
  • Toast: improve animation smoothness (#6065) (ee2c0a5)
  • types: improve DotPathKeys accuracy and GetItemKeys performance (#6077) (6f7af3e)
  • useEditorMenu: rank filtered results by relevance (f53484a)

🌐 Locales

👋 New Contributors

Read more