Conversation
Modal, Slideover, Drawer and Popover rendered with portal={false} hid
every floating layer opened inside them (Select, DatePicker,
DropdownMenu, Tooltip, a nested Modal, ...) whenever an ancestor set a
z-index above 50. The layers were portalled to <body> at z-50 while the
inline panel belonged to the higher stacking context.
While such a container is open, nested layers now mount into a host
placed right before its panel, in the same stacking context and one
level above it. The host is removed once the panel has unmounted, so the
closed DOM is unchanged, and portalled containers are not affected.
Closes #217
DatePicker and DateRangePicker positioned their calendar against the calendar icon button, which sits at the end of the field. With the default align="start" the popover opened at the icon's left edge, hundreds of pixels right of the field and over neighbouring content. The popover is now anchored to the field root, so it opens flush under the field's left edge, matching how Select places its list. align="center" now centres on the field and align="end" is unchanged. Closes #218
A horizontal NavigationMenu rendered every dropdown in one shared panel
pinned to the menu's left edge, so a trigger near the end opened a panel
hundreds of pixels away, detached from it when the content was narrow.
The panel now follows the open trigger. The component measures the
trigger's inline start and width; CSS places the panel with clamp() so it
stays inside the menu, using the panel width the viewport already
exposes. It slides between triggers, appears in place when the menu
first opens, follows the list when it scrolls, and respects dir="rtl".
Below the sm breakpoint the panel keeps its full width.
A new align prop ('start' | 'center' | 'end', default 'center') chooses
where the panel sits relative to the trigger. The docs page gains a
Dropdown Alignment section to switch it live.
The list also reserved 8px under its items for the overlay scrollbar at
all times. That room is now added only while the list overflows, so a
menu that fits no longer shows the gap.
Closes #220
The sliding indicator was positioned from the active trigger's offset, and only recomputed when the value, orientation or items changed, or when the list resized. Flipping the page from ltr to rtl mirrors the triggers without any of those, so the indicator kept its old offset and sat under the wrong tab, with the active label rendered in the on indicator color over the plain background. The indicator is now recomputed when a dir attribute changes anywhere in the document. A direction set only through CSS is still not detected. Closes #216
fix(portal): keep nested floating layers above inline containers
fix(date-picker): anchor the calendar popover to the whole field
…t-align fix(navigation-menu): open the dropdown panel under its trigger
fix(tabs): move the indicator when the text direction changes
mode-watcher was a required peer dependency while every other runtime library sits in dependencies. Users had to install it themselves, and package managers that do not auto install peers failed to resolve it at all. It moves to dependencies at the same range. toggleMode and resetConfig were referenced by the setup docs but never exported from the package root, so copying those snippets broke the build. A ThemeMode component now wraps the watcher and the mode functions are re-exported, which keeps the underlying library an implementation detail and leaves room to replace it later. ThemeModeButton chose its icon from mode.current, which is undefined during SSR, so the server always rendered the light branch. Svelte does not repair mismatched html blocks, so the wrong glyph stuck after a reload in dark mode. Both icons now render and CSS picks the visible one, and the accessible name no longer depends on the resolved mode. The docs pages are left untouched, so the findings about setup snippets stay open. Refs #224
The handle was a bare span carrying only onmousedown, with no role, no tabindex and no key handler. Keyboard users could not reach it at all, let alone resize a column. A probe measured the column staying at 150px after three arrow presses while a mouse drag moved it to 230px, and one Tab from a button above the table jumped straight past the whole table. The drag also listened for mousemove and mouseup on document, so touch and pen never started a resize, even though the element already carried touch-none and therefore blocked scrolling that began on it. It is now a focusable separator with aria-orientation, aria-valuenow, aria-valuemin, aria-valuemax and aria-valuetext, resized by the arrow keys with a larger step while shift is held, and by Home and End for the bounds. The drag moves onto usePointerDrag, which ColorPicker and Resizable already use, so every pointer type works. The svelte-ignore for static element interactions is gone, since the element is now interactive. One remains for the noninteractive tabindex rule, which misreads a separator carrying aria-valuenow as passive. That is the same false positive Resizable already suppresses. Closes #226
fix(theme-mode): export dark mode API, fix SSR icon mismatch
# Conflicts: # CHANGELOG.md
fix(table): make the column resize handle keyboard and touch accessible
The two slots were part of the public API but had no test coverage, and three separate things were wrong with them. isLeading and isTrailing ignored the slots, so the padding compound variants never applied. The same icon measured 36px of padding through the leadingIcon prop and 12px through the slot, leaving the content overlapping the text by 22px. Both flags now account for the slots. The slot wrapper carries pointer-events-none so that a decorative icon stays click through and clicking it focuses the field. That also made interactive slot content impossible to click: a button in a slot never received a single click, while the cursor still changed on hover. Pointer events are now re-enabled only on a wrapper that actually holds a slot, and only while the field is neither disabled nor loading, so a control inside a disabled field stays inert. A slot also took precedence over the loading branch, so a field with a slot went disabled during loading with no spinner and no other indicator. Loading now wins, matching how Button swaps its leading icon for the spinner. Also corrected the loading prop documentation, which claimed it optionally disables interaction while the input is always disabled while loading. That text ships in the published type declarations. Closes #229
Requested in #228. The first answer was to decline and document the composition instead, which was wrong on two counts: ThemeModeButton is 89 lines and does less, so thinness is not where this library draws its line, and the two extra bundled icons measure at about half a kilobyte before compression. The component wraps Input rather than reimplementing it the way InputTags and InputNumber do, because those two need to change what sits inside the field box while this one only needs a trailing control and blocks below. FormField and Form integration comes for free as a result: label association, error state and aria-describedby all flow through. What it handles: a visibility toggle whose accessible name follows the next action, purpose mapping to the correct autocomplete value for sign in, sign up and password change, a caps lock warning cleared on release or blur, and a guarantee that pasting is never intercepted. Scoring stays with the caller. strength takes a number and the component renders the meter, picks the colour and debounces the screen reader announcement so it fires on level changes rather than on every keystroke. A naive scorer is worse than no meter: counting character classes rates Password1! as strong while penalising a long passphrase for having no digit, and scoring properly needs a dictionary or a breach list, neither of which belongs in a UI library. Adds passwordShow and passwordHide to the icon defaults and regenerates the bundled set. Closes #228
fix(input): make leading and trailing slots usable
feat(input-password): add a password field with a caller scored meter
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Release 2.8.0. Minor, because the release adds a new component and three other additive changes. No export was removed: I diffed the published 2.7.0 surface against this build earlier in the cycle and it is purely additive.
Type of change
Behaviour changes worth checking on upgrade
None of these remove an export, but each is observable.
ThemeModeButtonnow has a fixed accessible name ofToggle themeinstead ofSwitch to light modeandSwitch to dark mode. Anything selecting the button by accessible name needs updating. This is the one I expect people to hit.ThemeModeButtonrenders two<svg>elements instead of one, with CSS choosing the visible one. The hidden icon isdisplay: none, so layout is unchanged and ordinarysvgstyling still applies. Selectors that count children no longer match.ThemeModeButtonno longer inherits its size from a surroundingFieldGroup, so the button and its icons always agree.Tablecolumn resize handle is now a focusableseparatorwithtabindexandaria-value*. Selectors aimed at a barespanwill not match.Inputslots now reserve padding and accept pointer events. An existinguiworkaround still behaves: the caller'sui.basewins over the variant padding, verified at 40px against 36px, and the control stays clickable.Changes
[2.8.0] - 2026-09-27
Added
Input. A visibility toggle whose accessible name follows the next action,purposemapping to the rightautocompletevalue for sign in, sign up and password change, a caps lock warning, and a guarantee that pasting 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. (#228)toggleMode,setMode,resetMode,mode,userPrefersModeandsystemPrefersModeare re-exported from the package root, alongsideresetConfig. The docs already referenced these; now they resolve. (#224)alignprop (start|center|end, defaultcenter) places the dropdown under the open trigger. (#220)Changed
mode-watchermoved frompeerDependenciestodependencies, matching every other runtime library. Dark mode now works without installing anything beyondsv5ui, including on package managers that do not auto install peers. (#224)Fixed
leadingSlotandtrailingSlotnow 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 decorativeleadingIconortrailingIconstays click through, and slot content is inert while the field is disabled or loading. The loading spinner also takes precedence over a slot instead of being swallowed by it. (#229)separatorwitharia-valuenow, arrow key resizing and a larger step while shift is held, plusHomeandEndfor 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. (#226)Toggle theme. (#224)portal={false}, nested floating layers (Select, DatePicker, DropdownMenu, Tooltip, ...) no longer hide behind the container when an ancestor has az-indexabove 50. (#217)ltrandrtl. (#216)Checklist
pnpm checkpasses (0 errors, 0 warnings)pnpm lintpassespnpm testpassespnpm buildpasses,publintreports no issuespackage.jsonCHANGELOG.mdrotated under[2.8.0]Notes
Tests: 3909 passing across 108 files, up from 3847 at 2.7.0.
One thing to watch during the CI run on this PR: several specs assert on icons that are not in the bundled set, so they fetch from the icon API at test time and can fail intermittently. I saw
AccordionandToggleGroupfail once this cycle and pass on a rerun. If CI goes red on those two, rerun before investigating.