Changelog

Latest changes, improvements, and fixes across Nuxt core and the official modules.

v3.15.0

🚀 Features

🐞 Bug Fixes

View changes on GitHub
v4.9.0

✨ 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:

nuxt.config.ts
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:

main.css
*,
::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 https://github.com/nuxt/ui/pull/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

  • @benjamincanac
  • @innocenzi
  • @zAlweNy26
  • @maximepvrt
  • @OrbisK
  • @mikenewbon
  • @al1maher
  • @emilsgulbis
  • @martinszeltins
  • @cydrickn
  • @neukinal
  • @hendrikheil
  • @johnson-jnr
  • @ReCoN-96

Full Changelog: https://github.com/nuxt/ui/compare/v4.8.2...v4.9.0

4.4.8 is a hotfix release to address an issue running the dev server on MacOS.

👉 Changelog

compare changes

🩹 Fixes

  • vite: Shorter socket name for macOs with tmp fallback (#35265)
  • kit: Respect type option in findPath (#35272)
  • deps: Update nuxt/scripts presets (905621594)
  • nuxt: Revert unhead dependency back to v2 (e6d578fea)

📖 Documentation

  • Fix many typos (#35266)
  • Explain static fallback pages (#35277)
  • Change null to undefined in data-fetching docs to match actual types (#35301)
  • Fix broken internal links, useAsyncData watch type, and NuxtError type (#35303)

❤️ Contributors

  • Daniel Roe (@danielroe)
  • Ali Mahmmoud (@AliMahmoudDev)
  • Quentin Macq (@quentinmcq)
  • Pranav Rajeshirke (@Pranav188)
  • Eduardo San Martin Morote (@posva)

3.21.8 is a hotfix release to address an issue running the dev server on MacOS.

👉 Changelog

compare changes

🩹 Fixes

  • vite: Shorter socket name for macOs with tmp fallback (#35265)
  • kit: Respect type option in findPath (#35272)
  • deps: Update nuxt/scripts presets (ff6b060dd)

📖 Documentation

  • Change null to undefined in data-fetching docs to match actual types (#35301)

❤️ Contributors

  • Daniel Roe (@danielroe)
  • Ali Mahmmoud (@AliMahmoudDev)
  • Quentin Macq (@quentinmcq)
  • Eduardo San Martin Morote (@posva)
v2.2.3

   🐞 Bug Fixes

    View changes on GitHub

4.4.7 is a security hotfix release.

👉 make sure to check https://github.com/nuxt/nuxt/security/advisories to view open advisories resolved by this release.

👉 Changelog

compare changes

🩹 Fixes

  • nitro: Assign noSSR before deciding payload extraction (#35108)
  • vite: Avoid filtering out dirs with shared prefix from allowDirs (#35112)
  • nuxt: Use resolve from pathe for buildCache path boundary check (#35111)
  • nuxt: Prevent sibling-directory traversal in test component wrapper (#35110)
  • nitro: Pass event data to isValid in dev clipboard-copy listener (#35109)
  • nuxt: Validate protocols in reloadNuxtApp path before reload (#35115)
  • vite: Prefix public asset virtuals with null byte (9e303b438)
  • nuxt: Re-run getCachedData after initial fetch (#35122)
  • nuxt: Propagate useFetch/useAsyncData factory types (#35133)
  • vite: Close vite dev server on nuxt close (a10a68abc)
  • kit,nuxt: Handle cancelling prompts to install packages (e84813229)
  • kit: Avoid excluding node-context files in legacy tsconfig (#35152)
  • nuxt: Handle missing payload in chunkError listener (#35155)
  • nuxt: Await in-lifght template generation when closing nuxt (#35181)
  • nuxt: Clarify page and layout usage warnings (#35184)
  • webpack: Surface compilation errors when stats.toString is empty (073b07851)
  • nuxt: Reject prototype-chain keys in the island registry (#35205)
  • nuxt: Apply isScriptProtocol guard to navigateTo open option (#35206)
  • nuxt: Prevent server-only page island from recursing via <NuxtPage> (#35198)
  • rspack,webpack: Require loopback host when missing same-origin signals (#35200)
  • nitro: Gate chrome devtools workspace endpoint to local requests (#35201)
  • nuxt: Escape props in <NuxtClientFallback> ssr output (#35199)
  • kit: Improve TS extension stripping/substitutions (#35233)
  • nuxt: Preserve .d.mts/.d.cts in resolveTypePaths (#35235)
  • nuxt: Escape <NoScript> slot content (4b054e9d9)
  • nuxt: Match route rules case-insensitively to mirror vue-router (07e39cd6f)
  • nuxt: Reject script-capable protocols in <NuxtLink> href (0103ce06f)
  • nuxt: Block path-normalization open redirect in navigateTo (2cce6fb02)
  • nuxt: Reject cross-origin paths in reloadNuxtApp (e447a793c)
  • vite: Bind vite-node IPC to a permissioned filesystem socket (1f9f4767a)

💅 Refactors

  • kit,nuxt,vite: Use es2023 array methods (#34980)
  • nuxt: Replace runInNewContext with AST walker (d72a89ef4)

📖 Documentation

  • Document vite client and server options (#35090)
  • Add dedicated module dependencies page (#35171)
  • Add nodeTsConfig and sharedTsConfig options (#35231)
  • Edit for clarity and grammar (#35214)

🏡 Chore

✅ Tests

  • Update test for js payload rendering (bdcb81536)
  • Cover add regression test for hmr in sibling local layers (#35125)
  • Improve reliability of hmr test (1d709b3cc)

🤖 CI

  • Always run all tests for 4.x/3.x (0dc4665cf)
  • Migrate from tibdex (ded29dc0f)
  • Add zizmor github actions check (#35089)
  • Update to agentscan v1.8.0 (#35120)
  • Automatically close PRs from automated accounts (#35161)
  • Disable provenance-change enforcement in dependency-review (a2cf43e68)

❤️ Contributors

  • Daniel Roe (@danielroe)
  • David Stack (@davidstackio)
  • David De Sloovere (@DavidDeSloovere)
  • anton-gor-dev (@anton-gor-dev)
  • Noah3521 (@Noah3521)
  • Shahar Aviram (@ShaharAviram1)
  • Matej Černý (@cernymatej)
  • Mohit Kumar (@mohitkum4r)
  • Matteo Gabriele (@MatteoGabriele)
  • Julien Huang (@huang-julien)
  • Damian Głowala (@DamianGlowala)

3.21.7 is the a security hotfix release.

👉 make sure to check https://github.com/nuxt/nuxt/security/advisories to view open advisories resolved by this release.

👉 Changelog

compare changes

🩹 Fixes

  • nitro: Assign noSSR before deciding payload extraction (#35108)
  • vite: Avoid filtering out dirs with shared prefix from allowDirs (#35112)
  • nuxt: Use resolve from pathe for buildCache path boundary check (#35111)
  • nuxt: Prevent sibling-directory traversal in test component wrapper (#35110)
  • nitro: Pass event data to isValid in dev clipboard-copy listener (#35109)
  • nuxt: Validate protocols in reloadNuxtApp path before reload (#35115)
  • vite: Resolve vite clientServer with ssr: false (#34959)
  • vite: Prefix public asset virtuals with null byte (38d330179)
  • nuxt: Handle missing payload in chunkError listener (#35155)
  • vite: Close vite dev server on nuxt close (d007d7060)
  • kit,nuxt: Handle cancelling prompts to install packages (59821a5ca)
  • nuxt: Await in-lifght template generation when closing nuxt (#35181)
  • webpack: Surface compilation errors when stats.toString is empty (71dccff2b)
  • kit: Improve TS extension stripping/substitutions (#35233)
  • nuxt: Preserve .d.mts/.d.cts in resolveTypePaths (#35235)
  • nuxt: Reject prototype-chain keys in the island registry (#35205)
  • nitro: Gate chrome devtools workspace endpoint to local requests (#35201)
  • nuxt: Escape props in <NuxtClientFallback> ssr output (#35199)
  • nuxt: Apply isScriptProtocol guard to navigateTo open option (#35206)
  • rspack,webpack: Require loopback host when missing same-origin signals (#35200)
  • nuxt: Absolutely resolve defu in app config template (40bedf0db)
  • nuxt: Match route rules case-insensitively to mirror vue-router (3f3e3fa7b)
  • nuxt: Escape <NoScript> slot content (7fea9fd68)
  • nuxt: Block path-normalization open redirect in navigateTo (1f2dd5e78)
  • nuxt: Reject cross-origin paths in reloadNuxtApp (6497d99dd)
  • vite: Bind vite-node IPC to a permissioned filesystem socket (c293bf950)
  • nuxt: Reject script-capable protocols in <NuxtLink> href (53284043d)
  • nuxt: Clarify page and layout usage warnings (#35184)
  • nuxt: Do not absolutely resolve defu (d11d7b1b5)

📖 Documentation

  • Edit for clarity and grammar (#35214)
  • Add dedicated module dependencies page (#35171)

🏡 Chore

  • Use execFileSync for safety in release scripts (9a455a658)
  • Assert there is always a tag (8da21fba8)
  • Fix type in test (bc2837125)
  • Fix lychee dynamic composable exclude (#35119)
  • Add autofix action tag in comment (70eba297f)
  • Update renovate minimum release age (27a6821a1)

✅ Tests

  • Update test for js payload rendering (b51a80840)
  • Improve reliability of hmr test (0078499f0)

🤖 CI

  • Always run all tests for 4.x/3.x (0519c0ade)
  • Update to agentscan v1.8.0 (#35120)
  • Automatically close PRs from automated accounts (#35161)
  • Migrate from tibdex (6277aedcb)
  • Disable provenance-change enforcement in dependency-review (1d4910eed)
  • Add zizmor github actions check (#35089)

❤️ Contributors

  • Daniel Roe (@danielroe)
  • Matej Černý (@cernymatej)
  • anton-gor-dev (@anton-gor-dev)
  • Julien Huang (@huang-julien)
  • David Stack (@davidstackio)
  • Noah3521 (@Noah3521)
  • Matteo Gabriele (@MatteoGabriele)
  • Mohit Kumar (@mohitkum4r)
  • Florian Heuberger (@Flo0806)
v1.2.0

   🚀 Features

   🐞 Bug Fixes

    View changes on GitHub
v4.8.1

🐛 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

  • @Akur1a
  • @bansal
  • @benjamincanac
  • @maximepvrt
  • @thanet-s

Full Changelog: https://github.com/nuxt/ui/compare/v4.8.0...v4.8.1