npm @nuxt/ui 4.10.0
v4.10.0

3 hours ago

✨ Highlights

🌟 InputRating component

A new InputRating component lets you display and collect ratings, with support for half-steps, custom length, clearing, hover preview and any icon:

<script setup lang="ts">
const value = shallowRef(3.5)
</script>

<template>
  <UInputRating v-model="value" :step="0.5" hoverable />
</template>

📦 Bundled, offline-ready icons

Nuxt UI now embeds the icons it uses into your build, so they render straight away during SSR and work fully offline instead of being fetched from the Iconify API at runtime. As long as the collection is installed locally, this happens automatically for Nuxt UI's own icons (the lucide collection by default), on both Nuxt and pure Vue/Vite.

On Nuxt this rides on @nuxt/icon's existing client bundle. On Vue the @nuxt/ui/vite plugin gains an icon.clientBundle option to bring the same bundling to Vite, either by listing icons or by scanning your source. This is powered by the standalone Vite plugin and utils added in @nuxt/icon v2.3.0:

import ui from '@nuxt/ui/vite'

export default defineConfig({
  plugins: [
    ui({
      icon: {
        clientBundle: {
          // list them explicitly...
          icons: ['lucide:heart', 'simple-icons:github'],
          // ...or scan your whole app
          scan: true
        }
      }
    })
  ]
})

Tip

Install each collection you use with @iconify-json/{collection_name} so its icons can be bundled. See the Icons integration for the details.

♻️ Keep overlay state with unmountOnHide

The Modal and Slideover components now accept the unmountOnHide prop. Set it to false to keep their content mounted while closed so form state, scroll position and expensive children survive open/close cycles:

<template>
  <UModal :unmount-on-hide="false">
    <UButton label="Open" />

    <template #content>
      <!-- kept alive when the modal is closed -->
    </template>
  </UModal>
</template>

🚀 Features

  • ChatPrompt: add body slot and focus highlight (#6709) (123184b)
  • ChatTool: add actions prop for tool approval (#6694) (1a3a9dc)
  • ContentSearch/DashboardSearch: support unmountOnHide prop (#6523) (f03f98b)
  • ContentToc: scroll list independently and center active link (#6697) (64b9f7d)
  • Drawer: add close and closeIcon props (#6669) (53e88a4)
  • Editor: allow disabling starter kit for plain text (#6713) (76d613c)
  • Empty: add loading and loadingIcon props (#6707) (86cd25c)
  • InputRating: new component (#5757) (cba2c2c)
  • Modal/Slideover: support unmountOnHide prop (#6626) (4deb61b), closes #5839 #3605
  • module: pre-bundle used icons into @nuxt/icon client bundle (#6633) (8d46034)
  • Popover: support enableTouch prop (#6626) (54125f3), closes #2346
  • Prompt: add claude action (#6693) (7bdcb13)
  • prose: configurable heading anchors and copy button (#6735) (f419731)
  • ScrollArea: add getScrollElement virtualize option (#6650) (a84de85)
  • Table: add getScrollElement virtualize option (#6657) (7e6d0f7)
  • unplugin: pre-bundle used icons into the Vue/Vite build (#6635) (dcf7cbc)

🐛 Bug Fixes

  • AuthForm: track password visibility per field (#6638) (0faeb92)
  • BlogPost/ChangelogVersion: format date in UTC to prevent hydration mismatch (#6722) (fe5bb23)
  • Button: allow inline event handlers with non-void return types (#6668) (269080a)
  • Carousel: prevent reset when plugin props use inline objects (f41d11e), closes #6221
  • ChatMessages: re-evaluate streaming indicator on each render (#6673) (5c986dd)
  • components: forward $attrs to root element when to prop is absent (#6628) (d3b5f1d)
  • components: forward data-slot to component root (#6643) (c9c5232)
  • components: respect prefers-reduced-motion in animations (#6723) (f951529)
  • ContentNavigation: key items by identity to prevent leading icon flash (#6640) (09fb52b)
  • defineShortcuts: add missing arrowdown to shiftable keys (#6702) (2128414)
  • defineShortcuts: defer standalone shortcuts that prefix a chain (#6703) (76ee176)
  • Editor: prevent suggestion menu blinking on keystroke (#6712) (7e6d8b0)
  • FileUpload: add aria-disabled attribute when disabled (#6653) (c3b2996)
  • inertia: make useRoute().fullPath reactive across navigations (#6696) (c256997)
  • Link: apply rel prop to internal links (#6677) (276302e)
  • Link: fall back to original path when localePath fails (#6637) (906e8fd)
  • LocaleSelect: add missing keys in emoji mapping (#6629) (fab73ab)
  • module: avoid unhead v2-only hookOnce in colors plugin (#6658) (e4ca579)
  • SelectMenu/InputMenu: only re-highlight first item with create-item (#6689) (a71dece)
  • Separator: forward fall-through attributes to root (#6641) (88baabc)
  • theme: use logical properties for RTL (#6724) (3179012)
  • types: type prose components in app config (#6711) (d56e39a)
  • useComponentProps: let app config defaultVariants override withDefaults (#6686) (f5e58fb)
  • useFileUpload: keep dropzone type filter reactive to accept (#6699) (000aba4)
  • useResizable: recover from corrupted persisted storage (#6704) (4c60745)
  • useResizable: share resize logic between mouse and touch (#6705) (730a54c)
  • useScrollspy: unobserve previous headings on update (#6700) (5944067)
  • useToast: dedupe duplicate ids and handle max of 0 (#6698) (71c623b)

🔥 Performances

  • components: drop the redundant inner in component extend (#6647) (3bf1a92)
  • module: declare sideEffects for barrel tree-shaking (#6729) (2cc2849)
  • types: decouple useComponentProps from the component-types barrel (#6648) (6576fb8)
  • types: import cross-component types from source, not the barrel (#6646) (7eab4bc)
  • vue: skip rewriting unchanged templates (#6730) (14b6001)

❤️ Contributors

Full Changelog: v4.9.0...v4.10.0

Don't miss a new ui release

NewReleases is sending notifications on new releases.