Release Notes
Changelog
Every release of sv5ui - new features, breaking changes, bug fixes, and improvements.
v2.9.0 Latest October 13, 2026 GitHub New Features
- ThemeMode - createInitialModeExpression returns the source of the script that sets the mode before first paint, for apps that inject it themselves with disableHeadScriptInjection under a strict Content Security Policy. The ColorMode , ResolvedColorMode , ThemeColors and InitialModeConfig types are exported alongside it. docs →
Improvements
- ThemeMode - dark mode is handled by sv5ui itself instead of wrapping mode-watcher . Props, exports and the localStorage keys ( mode-watcher-mode , mode-watcher-theme ) are unchanged, so stored preferences carry over. An app that still mounts its own <ModeWatcher /> stays in sync and gets one console warning per page load. mode-watcher stays in the dependencies until the next major, but importing from sv5ui is the supported path. Each mode change is also dispatched as a storage event on window in the same tab, so a storage listener that does not filter by key will see it. docs →
- Checkbox , CheckboxGroup , RadioGroup , Switch , Slider - aria-* props now land on the control instead of the wrapper, so an aria-label names the control. aria-hidden , class , style and data-* stay on the wrapper. Selectors such as [aria-label="Volume"] [role="slider"] become [role="slider"][aria-label="Volume"] . docs →
Bug Fixes
- ThemeMode - the injected script quotes the nonce and drops one that contains characters outside the CSP nonce set, and config values are escaped, so neither can break out of the script tag. docs →
- ThemeMode - a stored mode that is not light , dark or system falls back to defaultMode instead of applying dark before mount on a light system. docs →
- ThemeMode - with themeColors , the theme-color meta on first paint follows the mode on screen rather than the stored one, so system on a light system gets the light color. docs →
- ThemeMode - importing sv5ui no longer throws when localStorage is unavailable, as in a sandboxed iframe or with storage blocked. The mode is kept in memory instead. docs →
- ThemeModeButton - loading shows the spinner again instead of the mode icon. It had been hidden since 2.8.0. docs →
- ThemeModeButton - an onclick handler no longer replaces the toggle. It runs first, and calling preventDefault() in it cancels the toggle. docs →
- ThemeModeButton - toggles the dark class even when ThemeMode is not mounted. The class applied on page load still comes from ThemeMode . docs →
- Form controls - on Input , InputNumber , InputTags , Textarea , Select , SelectMenu , Rating , Checkbox , Switch , Slider , RadioGroup , CheckboxGroup and ColorPicker , an aria-describedby or aria-invalid of your own is no longer overwritten, and inside a FormField it merges with the field ids. Event handlers you pass are no longer replaced. docs →
- FormField - the label names each of those controls, including the ones a for attribute cannot reach. Slot content and the description stay announced next to an error, required sets aria-required on text inputs, and a control with its own id keeps its label and its Form errors. docs →
- Textarea , InputTags - leadingSlot and trailingSlot reserve room so they no longer cover the text, and a control inside them can be clicked, matching Input . docs →
- Textarea , Select , SelectMenu , Button - loading shows the spinner instead of a slot on the same side. docs →
- Breadcrumb - two items with the same label render side by side instead of crashing the page with a duplicate key error. docs →
v2.8.0 September 27, 2026 GitHub New Features
- InputPassword - a password field built on Input . A visibility toggle whose accessible name follows the next action, purpose mapping to the right autocomplete for sign in, sign up and password change, a Caps Lock warning, and pasting that is never blocked. An optional strength meter renders a score you supply: the library never judges a password itself, since scoring without a dictionary is misleading and a rule set that suits one policy penalises another. The screen reader announcement is debounced and fires on level changes rather than on every keystroke docs →
- ThemeMode - the dark mode handler for your root layout, replacing the setup that required a second package. toggleMode , setMode , resetMode , mode , userPrefersMode and systemPrefersMode are re-exported from the package root, alongside resetConfig docs →
- NavigationMenu gains align ( start , center or end , default center ), which places the dropdown under the open trigger. A panel wider than the space beside its trigger still clamps to the menu rather than hanging off the edge docs →
Improvements
- mode-watcher moved from peerDependencies to dependencies , matching every other runtime library. Dark mode now works without installing anything beyond sv5ui , including on package managers that do not install peers for you docs →
Bug Fixes
- Input - leadingSlot and trailingSlot reserve room in the field, so their content no longer sits on top of the text, and pointer events reach them, so a button placed in a slot is clickable. A decorative leadingIcon or trailingIcon stays click through, slot content is inert while the field is disabled or loading, and the loading spinner takes precedence over a slot instead of being swallowed by it docs →
- Table - the column resize handle is a focusable separator with aria-valuenow , arrow key resizing and a larger step while Shift is held, plus Home and End for the bounds. It was mouse only before: no role, no tabindex and no key handler, so keyboard users could not resize a column at all. The drag also moves to the shared pointer hook, so touch and pen work rather than mouse alone docs →
- ThemeModeButton - renders both mode icons and lets CSS pick the visible one, so server and client markup are identical and the wrong glyph no longer sticks after a reload in dark mode. The accessible name is a mode-independent Toggle theme docs →
- Modal , Slideover , Drawer and Popover - with portal={false} , nested floating layers (Select, DatePicker, DropdownMenu, Tooltip and the rest) no longer hide behind the container when an ancestor has a z-index above 50 docs →
- DatePicker and DateRangePicker - the calendar is anchored to the field instead of the calendar icon, so it opens under the field's start edge docs →
- NavigationMenu - the dropdown opens under the trigger that opened it, slides between triggers and stays inside the menu. The 8px gap under the items is now reserved only while the list overflows docs →
- Tabs - the indicator follows the active tab when the text direction flips between ltr and rtl docs →
v2.7.0 September 9, 2026 GitHub New Features
- ImageCropper - crop, zoom, rotate and flip an image in the browser, then export a Blob and a File at source resolution. Two interaction models, circular crops, a two-way area for reopening a saved crop, and autoCrop for live previews docs →
- Resizable - draggable panes with percentage sizing, pixel minimums, chained drags, collapsible and pinned panes, keyboard control and layouts persisted to localStorage docs →
- usePointerDrag - one drag gesture handled properly: pointer capture with a window fallback, moves coalesced per frame, axis locking, and the release position always reported. Now backs the ColorPicker saturation area and every Resizable handle docs →
- useSessionStorage - the storage hook scoped to the lifetime of a tab, for drafts and wizard progress docs →
- Editor gains imageCrop , which opens a cropper before the upload so the server receives the framed image rather than the original. Applies to the toolbar picker, a paste and a drop alike docs →
Improvements
- useLocalStorage takes a reactive key, goes inert on a null key so persistence can be optional, and gained enabled and remove() plus a storage option docs →
- Editor calls onImageUpload for pasted and dropped images too. Several pasted images upload in order, and a dropped image lands where it was dropped docs →
- Editor URL dialogs are real forms now, with labels, help text and icons, and the link dialog has an optional Display text field prefilled from the selection docs →
Bug Fixes
- Form no longer flags an untouched field: validateOn: 'focus' waits for the first blur, the rule 'input' already followed. eagerValidation on a FormField opts back into checking from the first focus docs →
- Editor link dialog no longer shows a validation error the moment it opens. The URL field takes focus and stays quiet until it is left docs →
Bug Fixes
- DropdownMenu and Popover arrows now carry the panel ring. Both are stroked along their slanted edges through the new arrowBorder ui slot, and the fill overlaps the panel edge so the outline reads as one unbroken line instead of cutting across the arrow base docs →
New Features
- ScrollArea - a styleable scrollbar over native scrolling, with per-axis control, four visibility modes, and a bindable viewport ref docs →
- ColorPicker - saturation area, hue and alpha sliders, preset swatches, an editable field and an eyedropper, with hex, rgb and hsl output docs →
Improvements
- Table scrolls on both axes inside a ScrollArea. New scrollArea prop and scroll ui slot; the root is now overflow-hidden, so a bare max-height is enough docs →
- Sidebar scrolls its content column inside a ScrollArea. New scrollArea prop; ui.content no longer carries flex-1 or the overflow classes docs →
- Slideover scrolls its body inside a ScrollArea. New scrollArea prop; ui.body no longer carries flex-1 or overflow-y-auto docs →
- NavigationMenu scrolls a horizontal list inside a ScrollArea. New scrollArea prop and scroll ui slot; vertical orientation is unaffected docs →
- Lightbox scrolls its thumbnail strip inside a ScrollArea. New scrollArea prop and thumbnailsScroll ui slot docs →
- New icons.eyeDropper configuration key, defaulting to lucide:pipette docs →
Bug Fixes
- DropdownMenu arrow was clipped by the panel it points from. The content is now overflow-visible when an arrow is present, and ui.arrow reaches the arrow element docs →
- Popover arrow rendered unstyled instead of taking the panel color docs →
- lucide:pipette is bundled for SSR, so the eyedropper button renders on the server rather than popping in after hydration docs →
New Features
- Tree - hierarchical tree view with multi-select, indeterminate state, full keyboard navigation, and bind:api docs →
- Lightbox - full-screen viewer for images, video and iframes, with zoom, swipe, thumbnails, captions and slideshow docs →
- NavigationMenu - horizontal mega-menu or vertical disclosures, with nested items, active-route detection, and a collapsed icon rail with flyouts docs →
- Sidebar - collapsible dashboard sidebar built on NavigationMenu: sidebar/floating/inset variants, icon or offcanvas collapse, persisted state, mobile drawer, and bind:api docs →
- SidebarTrigger - header button that collapses the sidebar on desktop and opens the mobile menu on small screens docs →
Improvements
- Icon - the default loading spinner is now lucide:loader-circle , replacing the deprecated lucide:loader-2 . It looks the same docs →
Bug Fixes
- Icon - built-in icons now render during SSR instead of loading from the Iconify API after hydration, so they no longer pop in and shift the layout on first paint. They also work offline. Adds ~1.2KB gzip docs →
New Features
- DatePicker - segmented date input with a calendar popover, granularity, min/max, locale, and an optional time field docs →
- DateRangePicker - start/end segmented inputs with a two-month range calendar and minDays/maxDays constraints docs →
- TimeField - segmented time input with granularity, 12/24-hour cycle, and min/max limits docs →
- InputNumber - numeric input with stepper buttons, locale-aware formatting, and min/max clamping docs →
- InputTags - tag input rendering values as removable badges with delimiter, paste, and duplicate handling docs →
- Rating - star rating input with half steps, readonly display, and custom icons docs →
- Toggle - two-state pressed button with icon-only mode and aria-pressed semantics docs →
- ToggleGroup - single or multiple selection with segmented-control styling and roving focus docs →
Improvements
- Calendar - disabled dates now dim with opacity-50, and range-selection styling applies to range mode docs →
New Features
- Tour - spotlight product tour: per-step placement, async guards, waitForTarget, centered dialog steps docs →
- useTour - headless Tour controller (start/stop/next/prev/goTo) with persistence for multi-page tours docs →
- Error - pre-built error page with clear button and svelte:boundary reset support docs →
- Header - sticky app header with brand link, layout areas, and a Modal/Slideover/Drawer mobile menu docs →
- Main - content container filling the viewport below the header docs →
- Footer / FooterColumns - app footer with link-group grid, active links, and external indicators docs →
- App shell height contract: --ui-header-height CSS variable shared by Header, Main, and Error docs →
- Icons config: new defaults menu and external docs →
New Features
- useEventListener - attach DOM event listeners reactively docs →
- useResizeObserver / useElementSize - track element dimensions docs →
- useScrollLock - lock page or element scroll docs →
- useFocusTrap - trap keyboard focus inside a container docs →
- useLocalStorage - reactive localStorage with SSR safety docs →
- useThrottle - throttle rapidly-firing values docs →
- useIntersectionObserver - observe viewport intersection docs →
- useTimeout - cancelable, restartable setTimeout docs →
- useInterval - pausable setInterval with reactive delay docs →
- useDebouncedState - debounced state with immediate setter docs →
Bug Fixes
- SelectMenu - trigger changed to <div role="button"> , fixes SSR hydration mismatch. Update custom selectors to [data-combobox-trigger] . docs →
- DropdownMenu / ContextMenu - checkbox and radio checked-indicator icon now correctly sized. docs →
Improvements
- Packaging - dist/*.svelte files preprocessed to plain JS, fixes Rolldown/Vite 8 parse errors.
- Hook types - barrel switched to export * ; per-hook return-type interfaces are now inferred.
Breaking Changes
- Modal, Slideover, Drawer - trigger snippet now receives a props argument that must be spread onto the trigger element. docs →
New Features
- Editor - onImageUploadError callback prop for handling image upload failures. docs →
- Editor - image URL validation: blocks javascript: , SVG data URIs, and data:text/* schemes. docs →
- Command - exports CommandGroup and CommandItem types. docs →
- Input - exports InputValue type. docs →
Improvements
- data-* passthrough tightened to string | number | boolean | null | undefined across Icon, Tabs, Pagination, Command, Select, SelectMenu, Collapsible.
- Performance - memoized tailwind-variants in Accordion, Progress, Switch, Stepper, ThemeModeButton, Skeleton.
- Editor - lazy-loads tiptap-markdown and table extension to reduce initial bundle.
- SelectMenu - 200ms search debounce to reduce re-renders during typing. docs →
Bug Fixes
- Calendar - year navigation buttons now work correctly. docs →
- RadioGroup - <legend> element now has correct accessibility attributes. docs →
- FileUpload - blob URLs properly cleaned up on unmount. docs →
Breaking Changes
- DropdownMenu - trigger snippet now receives { open, props } . Spread props onto the focusable trigger element. docs →
- Removed: wireFormEvents helper - use useFormFieldEmit instead. docs →
- Removed: Select defaultValue prop - set initial value via bind:value . docs →
- Removed: TabsItem.slot prop. docs →
- Removed: DropdownMenuRadioGroup.name prop. docs →
New Features
- Separator - new position prop: start | center | end for label positioning. docs →
- Button / Link - validates native form and anchor HTML attributes. docs →
- Icon - validates SVG, aria-* , data-* , and event handler attributes. docs →
- Collapsible, Tabs, Pagination - forward root HTML attributes.
Bug Fixes
- Alert - default variant corrected from soft to solid . docs →
- Input - avatar takes precedence over leadingIcon when both provided. docs →
- AvatarGroup - items now render left-to-right. docs →
- Pagination - prev/next buttons now have aria-label attributes. docs →
- SelectMenu - search field no longer inherits parent FormField validation context. docs →
New Features
- Carousel - new component built on Embla Carousel. Supports arrows, dots, autoplay, fade/slide transitions, responsive breakpoints, and bind:api . docs →
- Select / SelectMenu - multiple prop for multi-selection. value becomes string[] . docs →
- SelectMenu - createItem prop lets users add typed values not in the items list. docs →
- Modal / Slideover - size prop: sm | md | lg | xl | full . docs →
- Modal / Slideover - transition prop: none | fade | slide | scale . docs →
- FileUpload - maxSize (bytes per file) and maxFiles validation props. docs →
- FileUpload - onReject callback fires with files rejected by accept , maxSize , or maxFiles . docs →
- Calendar - isDateHighlightable predicate for marking special dates with a dot indicator. docs →
- Calendar - maxDays now wired for type="multiple" . docs →
- PinInput - loading and loadingIcon props for OTP verification flows. docs →
Improvements
- FileUpload / Calendar - now read parent FormField context; errors propagate to aria-invalid and visual styles. docs →