v1.0.0
Overview
🚀 Features
- locale: add
ti()so components carry inline English aria labels without bundling a locale (WCAG 4.1.2) (#372)
🔧 Bug Fixes
- Dialog, Snackbar: overlays can teleport into the topmost open modal so snackbars shown over a modal Dialog appear above it and stay interactive (#279)
- Switch,Form,Slider: correct ARIA states for mixed, native validation, and grouped form controls (#543)
- Avatar,Scrim,Popover,Tooltip,Select,Toggle: restore dropped alt text and complete missing ARIA wiring (#543)
- build: ship type declarations for the
@vuetify/v0/browserentry (#443) - Button: don't auto-set aria-label in renderless mode (#390)
- Combobox: route ComboboxEmpty default slot text through useLocale (#546)
- createSelection: reject disabled items in multiple-mode
apply()(#426) - Carousel: pause autoplay while keyboard focus is inside the carousel (#625)
- createSelection: disabled tickets are now inert to unselect and toggle (#585)
- createNested: leaf-mode parent unselect respects mandatory atomically instead of half-clearing the branch (#579)
- createNumberField: commit now no-ops while disabled or readonly, matching increment and decrement (#584)
- createProgress: fromValue offsets by min so ProgressFill width matches the ARIA percent (#580)
- createSelection: apply fully replaces the selection under multiple+mandatory instead of stranding a stale id (#582)
- createSlider: thumb operations (set, up, down, floor, ceil) now no-op while disabled, as documented (#583)
- Splitter: give the resize handle a default localized
aria-label(#627) - Treeview: expose the active node to assistive technology via
aria-current(#626) - createForm: submit no longer reports failure when a field validation was superseded by a newer concurrent call (#581)
- NumberField: pass parsed value directly to commit() so typed values correctly propagate to the parent v-model on blur and Enter (#371)
- bring component ARIA/data attributes into PHILOSOPHY §3.6 compliance (#451)
- usePopover: coerce the synthesized
anchor-name/position-anchorcustom-ident to a valid charset (#416) - useProxyModel: apply the current v-model to late-registering tickets (#587)
- createRegistry: dispatch batched events even when the batch callback throws (#570)
- createRegistry: heal offboard reindex, id identity, and batched field-only upserts (#565)
- security: apply prototype-pollution and CSS-injection guards flagged in the security review (#489)
- useRtl,useTheme: keep SSR head entries in sync with reactive state (#606)
- useRules: accept spec-compliant Standard Schema issue paths (#500)
- Switch: keep
Switch.Thumbvisible in every state (#586) - useTheme: remove the adopted stylesheet on V0 adapter dispose (#424)
- useTheme: apply
cspNonceon the SSR head path (#441) - useTheme: validate the theme adapter
prefixagainstSAFE_IDENT(#440) - createTokens: mutators now forward their
eventargument andticket.valueis typed accurately underflat: true(#564) - createTokens:
resolve()no longer returns inherited prototype members (#427) - createTokens: follow a
{alias}reached through a segment path (#566) - Tooltip: expose anchor styles on Tooltip.Activator's renderless slot (#648)
- Treeview: don't intercept keyboard events originating from embedded interactive controls (switches, comboboxes, etc.) so they can handle their own key events (#370)
- Treeview: let keyboard focus reach controls inside items (#341)
- useStack: make ticket blocking/scrim reactive (#418)
- useStack: don't share the fallback stack across SSR requests (#442)
- createValidation: stop
isValidatingstickingtruewhen a silent validation interleaves an async one (#588)
🔥 Performance Improvements
- createDataGrid: dramatically faster sorting, drag-reordering, and initialization on large grids (#555)
- Overflow: cache item visibility in a hidden-index set, dropping per-item O(n) rank scans to O(1) (whole-list visibility goes from O(n²) to O(n) per resize) (#417)
- createRegistry: memoize reactive keys/values/entries behind a version signal (#540)
- createRegistry: use O(1) ticket.index for unregister splice locate (with indexOf fallback); avoid values() allocation/copy in seek first/last; never eagerly drain reindex in unregister to preserve the lazy contract (#531)
- createRegistry: skip version notification on field-only upsert (#542)
Other Commits
- plugins: lock in SSR safety for every plugin composable (#569)
- maturity: promote the v1 stable set to
stable(#470) - maturity: promote the 1.0 component spine to
stable(#655)
Minor Changes
-
#372
d075615Thanks @sridhar-3009! - feat(locale): addti()so components carry inline English aria labels without bundling a locale (WCAG 4.1.2)locale.ti(key, ...params)("translate if exists") returns the translation orundefinedinstead of echoing the key, enabling theti(key) ?? '<default>'pattern at call sites- Every v0 component now provides a built-in English aria label via
ti(...) ?? '<default>', so apps with no locale plugin get meaningful accessible names — with zero strings bundled into the runtime fallback @vuetify/v0/locale/messages/enis exposed as an optional export: the canonical English catalog, handy for seeding a translation or registering full English coverage (never imported by the runtime)
-
#397
19aac62Thanks @johnleider! - fix(Dialog, Snackbar): overlays can teleport into the topmost open modal so snackbars shown over a modal Dialog appear above it and stay interactive (#279)A native modal
<dialog>(showModal()) is promoted to the browser top layer, which paints above allz-indexand makes everything outside its subtree inert — so an overlay teleported tobodyrendered beneath the dialog and was unclickable. Overlays can now teleport into the top-layer subtree instead:Snackbar.Portalnow defaultsteleportto'top-layer', mounting into the topmost open modal<dialog>when one is open and falling back tobodyotherwise.teleport="body"(always body) and:teleport="false"(render inline) remain escape hatches.Portalaccepts a newto="top-layer"token that resolves to the topmost modal element, orbodywhen no modal is open.useStackexposes a newtopElementcontext field and aneloption onregister(), so modal dialogs publish their element as the teleport target.useClickOutsidebounds mode no longer treats a strict DOM descendant as an outside click, so clicking an overlay teleported into a<dialog>(e.g. a Snackbar and its close button) no longer dismisses the dialog. Backdrop clicks (target is the dialog itself) still close it.
Patch Changes
-
#619
95d2d34Thanks @johnleider! - fix(Switch,Form,Slider): correct ARIA states for mixed, native validation, and grouped form controls (#543)Switch.RootandSwitch.SelectAllno longer emit the spec-invalidaria-checked="mixed"; the value is clamped tofalsewhile indeterminate, so screen readers announce a valid switch state. Style indeterminate switches withdata-state="indeterminate"as before.Switch.ThumbandSwitch.Trackare now markedaria-hidden="true", hiding the decorative visuals from assistive technology.Form.Rootnow rendersnovalidateby default, so the browser's native constraint popups no longer block submit before v0's async validation runs. Opt back into native constraint validation with:novalidate="false".Slider.Rootnow exposesrole="group"plus optionallabel/ariaLabelledbyprops, giving multi-thumb sliders an accessible group name.
-
#618
d611c03Thanks @johnleider! - fix(Avatar,Scrim,Popover,Tooltip,Select,Toggle): restore dropped alt text and complete missing ARIA wiring (#543)Avatar.Imagenow accepts analtprop and passes consumer attributes (alt,aria-label, ...) through to the rendered element — previously they were silently droppedScrimbackdrops are hidden from assistive technology witharia-hidden="true"Popover.Activatorexplicitly exposesaria-expandedandaria-controlsinstead of relying on inconsistent nativepopovertargetmappingTooltip.Contentcloses on Escape when focus is inside interactive tooltip contentSelect.Activatorreflects the disabled state (aria-disabled+ nativedisabled) and stays keyboard-focusable when rendered as a non-button element;Select.Contentnames its listbox viaaria-labelledbyToggle.Groupgainslabel,ariaLabelledby, andariaDescribedbyprops so the group can be named
-
#443
2f4275cThanks @johnleider! - fix(build): ship type declarations for the@vuetify/v0/browserentry —./browsermapped to./dist/browser/index.jswith no.d.ts, soare-the-types-wrongflagged itUntypedResolutionand TypeScript consumers importing@vuetify/v0/browsergot no types. The browser bundle now emitsdist/browser/index.d.ts(it bundles the samesrc/index.tsas the main entry, so its types are identical), and therepo:exportsattw check no longer needs to exclude the browser entrypoint. -
#390
5db6a0dThanks @johnleider! - fix(Button): don't auto-set aria-label in renderless mode — in renderless mode the consumer owns the DOM and is responsible for the accessible name; the automatic icon-only fallback no longer overrides visible text in mixed-content renderless usagesAlso migrates the solo icon-only fallback to
locale.ti('Button.label') ?? 'Button', matching the inline accessible-name default every other component now ships, so an unconfigured app gets"Button"instead of the rawButton.labelkey. -
#546
03b298fThanks @sridhar-3009! - fix(Combobox): route ComboboxEmpty default slot text through useLocaleThe hardcoded
"No results"fallback inComboboxEmptywas not going throughuseLocale, violating PHILOSOPHY §5.5 (locale-first strings). Added aCombobox.noResultskey to the English message bundle and changed the default slot content to{{ locale.ti('Combobox.noResults') ?? 'No results' }}, matching the pattern used byDialog.Closeand other components. Consumers who override the default slot are unaffected. -
#555
9c04eadThanks @johnleider! - perf(createDataGrid): dramatically faster sorting, drag-reordering, and initialization on large grids (#555)Grids with thousands of rows are far faster to sort, drag-reorder, and build — a 10k-row sort is ~28× faster, drag-reordering ~6.5×, and initial construction ~2×. No API change and no migration: existing grids get the speedup on upgrade.
-
#426
dc0fc00Thanks @johnleider! - fix(createSelection): reject disabled items in multiple-modeapply()— the v-model sync path (apply()) could select a disabled item even thoughselect/unselect/toggleall reject them, violating the "disabled = all selection ops are no-ops" contract.createModel.apply()'s browse-fallback now routes throughselect()(which guards instance- and ticket-leveldisabled), andcreateSelection.apply()'s multiple branch gains an inline per-ticket guard before adding (kept inline rather than routed throughselect()so the single-modemultiple: trueoverride still works). The ref-write value-sync path is untouched. Affects multiple-modecreateSelection/createGroup/createNestedviauseProxyModel. -
#625
584668dThanks @sridhar-3009! - fix(Carousel): pause autoplay while keyboard focus is inside the carousel (#625)Moving focus into the carousel now pauses auto-rotation and moving focus out resumes it, mirroring the existing pointer/touch behavior and satisfying WCAG 2.2.2 (Pause, Stop, Hide).
-
#585
da2e0c1Thanks @johnleider! - fix(createSelection): disabled tickets are now inert to unselect and toggleGesture operations (select, unselect, toggle) no longer mutate disabled tickets in either direction. Wholesale operations (apply/v-model, selectAll, cascade propagation, clear) still drain disabled ids so state can never get stuck.
-
#579
23e7a0bThanks @johnleider! - fix(createNested): leaf-mode parent unselect respects mandatory atomically instead of half-clearing the branch -
#584
df823caThanks @johnleider! - fix(createNumberField): commit now no-ops while disabled or readonly, matching increment and decrement -
#580
52b0ea8Thanks @johnleider! - fix(createProgress): fromValue offsets by min so ProgressFill width matches the ARIA percent -
#582
e741325Thanks @johnleider! - fix(createSelection): apply fully replaces the selection under multiple+mandatory instead of stranding a stale id -
#583
9127759Thanks @johnleider! - fix(createSlider): thumb operations (set, up, down, floor, ceil) now no-op while disabled, as documented -
#627
396ea49Thanks @sridhar-3009! - fix(Splitter): give the resize handle a default localizedaria-label(#627)A
Splitter.Handlewithout an explicitlabelnow falls back to the localizedSplitter.handlestring ("Resize"), sorole="separator"always exposes an accessible name to assistive technology (WCAG 4.1.2, Name/Role/Value). -
#626
a1df426Thanks @sridhar-3009! - fix(Treeview): expose the active node to assistive technology viaaria-current(#626)Navigation trees without checkbox selection now convey the current node — the active
treeitememitsaria-current="true"alongside the existingaria-selected, so screen readers can announce the focused node. -
#581
cdc9fb5Thanks @johnleider! - fix(createForm): submit no longer reports failure when a field validation was superseded by a newer concurrent callA superseded validate() now resolves to the latest validation's outcome instead of false, so double-submits and concurrent field validation report the form's actual validity.
-
#371
3ee1d85Thanks @sridhar-3009! - fix(NumberField): pass parsed value directly to commit() so typed values correctly propagate to the parent v-model on blur and Enter — avoids reading the stale model before Vue's reactivity round-trip completes -
#417
0cd2de5Thanks @johnleider! - perf(Overflow): cache item visibility in a hidden-index set, dropping per-item O(n) rank scans to O(1) (whole-list visibility goes from O(n²) to O(n) per resize) -
#451
fe12826Thanks @johnleider! - fix: bring component ARIA/data attributes into PHILOSOPHY §3.6 compliance —ExpansionPanelcontent now emitsdata-selectedastrue | undefined(it was a raw boolean, so[data-selected]matched even when unselected), andSliderthumb /Ratingroot now emitaria-disabledas a concrete boolean (it wastrue | undefined, which dropped the attribute when not disabled). -
#416
6e8f86cThanks @johnleider! - fix(usePopover): coerce the synthesizedanchor-name/position-anchorcustom-ident to a valid charsetA consumer-supplied
id(or activatortarget/ content_id) containing non-ident characters produced an invalid--${id}custom-property name. The browser rejects it on the client (style.setPropertydrops the whole inline value), so anchor positioning silently broke. The interpolated identifier is now coerced to[a-zA-Z0-9_-], mirroring theSAFE_IDENTguardThemeAdapteralready applies. The rawidis still used verbatim for the DOM element id and thepopovertargetlinkage — only the CSS custom-ident is coerced, so the native popover wiring is unchanged. -
#587
7f01ea0Thanks @johnleider! - fix(useProxyModel): apply the current v-model to late-registering tickets (#587) — when the v-model changed before a value's ticket registered (e.g. tabs, carousels, or button groups whose items load asynchronously), the stale value was still selected once the ticket arrived, leaving the registry out of sync with the v-model. Late registration now honours the current model value. -
#540
2ed9618Thanks @johnleider! - perf(createRegistry): memoize reactive keys/values/entries behind a version signalReactive-mode iteration reads previously bypassed the result cache and read the
order array through its shallowReactive proxy — one trap per index and, inside
an effect, one tracked dependency per index. Reads now touch a single version
signal (bumped on every structural mutation) and share the non-reactive cache,
making reactive reads O(1) between mutations and giving subscribing effects one
dependency regardless of collection size. Mid-batch reads now always reflect
mutations already applied instead of a stale pre-batch snapshot. -
#570
e770c89Thanks @johnleider! - fix(createRegistry): dispatch batched events even when the batch callback throws (#570)Event-driven consumers (e.g.
useProxyRegistrysnapshots) no longer go stale when a batch oronboardthrows after some mutations already applied — the queued events for those applied mutations now flush regardless of whether the callback completes. -
#565
05be673Thanks @johnleider! - fix(createRegistry): heal offboard reindex, id identity, and batched field-only upsertsThree correctness fixes to the registry foundation:
offboardnow eagerly reindexes when index-derived tickets shift position, sovalues()/entries()anduseProxyRegistryconsumers see correctedindex/valueimmediately — previously a mid-listoffboard()left the default (index-valued) survivors stale until some later position-reading call drained the deferred reindex, and iteration-only consumers never healed. It also drops the stale iteration cache before the removals so a sync effect firing mid-offboardnever observes removed ids.offboardpreserves a suppliedidacross a transfer even when the ticket has no explicit value. It previously usedvalueIsIndexas a proxy for "id was auto-generated" and stripped the id of any value-less ticket, soregister({ id: 'a' })→offboard(['a'])returned{}and lost identity. Now only ids the registry itself minted are stripped. Behavior delta for the selection chain:createModeland everything built on it mint ids in their wrappers before callingregister, so those ids read as supplied to the base registry —offboardnow preserves them where it previously stripped them for value-less tickets. Downstream transfers (e.g. moving items between selections) keep their identity instead of getting a fresh id on re-onboard.batch()no longer re-notifies iteration subscribers for a field-only upsert (or an empty batch), matching the non-batchedupsertcontract (§4.4): a batch that changes no membership or order leaves version subscribers untouched.
-
#531
49e4f8bThanks @johnleider! - perf(createRegistry): use O(1) ticket.index for unregister splice locate (with indexOf fallback); avoid values() allocation/copy in seek first/last; never eagerly drain reindex in unregister to preserve the lazy contract -
#489
5c6d087Thanks @johnleider! - fix(security): apply prototype-pollution and CSS-injection guards flagged in the security reviewuseFeaturesadapters (LaunchDarkly / Flagsmith / PostHog) now skipUNSAFE_KEYS(__proto__/constructor/prototype) flag names when building the flags object, matching the guard already used bymergeDeep,usePermissions, andcreateTokensuseLocalerestore()validates the persisted value withisString/isNumberguards before applying it instead of blind-castingsaved as ID, completing the persist/restore sweep (useThemeanduseRtlnow use the same guards)ThemeAdapter'sUNSAFE_CSSdenylist is hardened against declaration injection: it now also rejects;,\(CSS escape evasion), and the URL-loading functionssrc()/image()/image-set()/cross-fade()V0ErrorfiltersUNSAFE_KEYSwhen copying caller-supplied error details onto the instance
-
#606
9ca3fb3Thanks @sridhar-3009! - fix(useRtl,useTheme): keep SSR head entries in sync with reactive state (#606)During server rendering, the
dirattribute,data-theme, and injected theme styles now update viaentry.patchwhen RTL or theme state changes after the initial head push — previously the first-rendered values were frozen for the rest of the request. Adapter disposal also cleans up the new watchers alongside the head entry. -
#569
e653ef5Thanks @sridhar-3009! - test(plugins): lock in SSR safety for every plugin composable (#569)Adds an SSR contract test to each plugin composable — no throw without a provider, and a fresh fallback per call so nothing leaks between requests — plus a guard that fails if a new plugin ships without one. The
useStackleak these guard against was fixed in #442. -
#470
38b27edThanks @johnleider! - chore(maturity): promote the v1 stable set tostable— the selection family (createModel,createSelection,createSingle,createStep,createGroup,createNested),createRegistry, and the plugin trio (useTheme,useStorage,useBreakpoints) are now API-locked for 1.0. They join the already-stable foundation (createContext,createPlugin,createTrinity) and observer (useIntersectionObserver,useMutationObserver,useResizeObserver) composables, bringing the stable surface to 16 composables plus the 17 stable utilities. -
#655
65952f2Thanks @johnleider! - chore(maturity): promote the 1.0 component spine tostable— 13 headless components are now API-locked for 1.0: the primitivesAtomandAspectRatio, the providersTheme,Group,Selection,Single, andStep, theTabs,Toggle, andCollapsibledisclosure/interaction components, and theCheckbox,Radio, andSwitchform controls. Three supporting composables graduate with them —useProxyModel,toElement, andtoArray— because every promoted component rests on them, and a stable component cannot sit on apreviewlogic layer. No behavior or signature changes: this is a stability commitment, not a code change, so no consumer action is required. -
#500
ffc4e5aThanks @johnleider! - fix(useRules): accept spec-compliant Standard Schema issue pathsWidens the vendored
StandardSchemaV1issuepathtyping toReadonlyArray<PropertyKey | PathSegment>per the Standard Schema v1 spec, so schemas typed with@standard-schema/spec(Valibot, Zod, ArkType) are assignable torulesagain. -
#586
562bd14Thanks @johnleider! - fix(Switch): keepSwitch.Thumbvisible in every state — it no longer forces an inlinevisibility: hiddenwhen the switch is off. The thumb had inherited the "present-when-on" indicator template fromCheckbox/Radio/Toggle, but a switch knob is always visible and slides between positions. The inline style also sat at the top of the cascade, forcing consumers to override it withvisibility: visible !important. Drive the off/on appearance from thedata-stateattribute (checked/unchecked/indeterminate) — e.g.translate-x-1 data-[state=checked]:translate-x-6— which now animates directly from the off position.Switch.Thumb's slotattrsno longer includes astylekey. -
#424
ceaeba8Thanks @johnleider! - fix(useTheme): remove the adopted stylesheet on V0 adapter dispose — the browser adapter (V0StyleSheetThemeAdapter) appended aCSSStyleSheettodocument.adoptedStyleSheetsinupsert()butdispose()only stopped the Vue watchers, leaking orphaned sheets on repeated mount/unmount (HMR, test suites, micro-frontend teardown). Dispose now filters the sheet out ofadoptedStyleSheetsand clears the ref across all three dispose paths, mirroring the sibling unhead adapter. Follow-up to the leak-safe adapter lifecycle work. -
#441
bf61d28Thanks @johnleider! - fix(useTheme): applycspNonceon the SSR head path —V0StyleSheetThemeAdapteraccepted acspNonceoption but never applied it: the SSRhead.push<style>was emitted without the nonce, so strict-CSP (style-src 'nonce-…') apps had their server-rendered theme styles blocked (FOUC until client hydration). The nonce is now threaded into the SSR style entry, andV0UnheadThemeAdapteraccepts and forwardscspNoncetoo (initial push, reactive patch, andupdate()). The nonce is added only when set, so non-CSP usage is unchanged. The clientadoptedStyleSheetspath correctly needs no nonce. -
#440
999c41fThanks @johnleider! - fix(useTheme): validate the theme adapterprefixagainstSAFE_IDENT—ThemeAdapter.generate()sanitized theme names, color keys, and values, but interpolated the adapterprefixinto the generated CSS (--${prefix}-…,var(--${prefix}-on-background)) unvalidated, so a malformed prefix (e.g. containing}) could break out of the declaration block and inject arbitrary CSS rules. The constructor now rejects any prefix that doesn't matchSAFE_IDENT(/^[a-zA-Z0-9_-]+$/) with aV0Error(V0_THEME_INVALID_PREFIX), mirroring the guard already applied to adjacent inputs and theV0_PALETTE_INVALID_SEEDprecedent. BothV0StyleSheetThemeAdapterand the unhead adapter inherit it. Non-breaking — valid prefixes already match. -
#564
ef7316bThanks @johnleider! - fix(createTokens): mutators now forward theireventargument andticket.valueis typed accurately underflat: true(#564)upsert(and the other registry mutators) silently dropped the optionaleventargument, so custom events never emitted for token registries; the wrappers now forward it and match the inheritedRegistryContextsignatures.TokenValuealso widens to includeTokenCollectionsoticket.valuereflects the nested objects stored underflat: true— the modeuseTheme/useFeaturesrely on — instead of claiming leaf/alias only.If you exhaustively narrow a
TokenValue(orticket.value) in aswitch/type guard, add aTokenCollection(object) branch — the union now has an object member alongside the primitive and alias cases. -
#427
0c355e6Thanks @johnleider! - fix(createTokens):resolve()no longer returns inherited prototype members — the alias-path walk usedsegment in current, which traverses the prototype chain, so resolving a path whose final segment named anObject.prototypemember (constructor,toString,hasOwnProperty,__proto__, …) returned that builtin instead ofundefined+ the "Path not found" warning.resolve()now mirrorsflatten()'s guard (UNSAFE_KEYS+Object.prototype.hasOwnProperty.call). Correctness/defense-in-depth — config and the resolve argument are developer-authored, so this is a consistency fix, not a security fix. -
#589
3b5565dThanks @johnleider! - fix(createTokens): follow a{alias}reached through a segment path (#566)resolve()now re-resolves an alias that a dotted-segment lookup lands on, instead of returning the raw'{alias}'string. This is visible underflat: true(where nested groups are stored whole and addressed by segment), souseTheme— which resolves theme colors through aflat: truetoken table — no longer drops or leaks an unresolved{alias}for a palette entry that is itself an alias. The leaf-value branch already followed terminal aliases; the segment branch now matches it. -
#648
4c2ede3Thanks @johnleider! - fix(Tooltip): expose anchor styles on Tooltip.Activator's renderless slotTooltip.Activatornow surfaces its CSS anchor-positioning styles as astylesslot prop (mirroringTooltip.Content). In renderless mode the activator no longer renders its own element, so previously the anchor name was lost and the tooltip content could not position. Consumers can now bindattrsand applystylesonto their own trigger element — e.g. attaching a tooltip to a native<button type="submit">without the activator overriding itstype. -
#542
76ca193Thanks @johnleider! - perf(createRegistry): skip version notification on field-only upsertPatching an existing ticket via
upsertno longer re-notifies version-subscribed
iterating effects — membership and order are unchanged, and field changes already
propagate through the shallowReactive ticket proxies and theupdate:ticket
event. The read cache still refreshes so event-driven snapshot consumers
(useProxyRegistry) observe a fresh array identity. This restores the pre-#540
iteration granularity for field patches. -
#370
7bd450cThanks @sridhar-3009! - fix(Treeview): don't intercept keyboard events originating from embedded interactive controls (switches, comboboxes, etc.) so they can handle their own key events -
#341
ab6da17Thanks @J-Sek! - fix(Treeview): let keyboard focus reach controls inside itemsTab and Shift+Tab now move focus between a tree node and the focusable controls it contains. Tabbing out of a control advances from that control's own row, and
aria-disabledcontrols are skipped. -
#418
9063b2cThanks @johnleider! - fix(useStack): make ticket blocking/scrim reactiveregister()now acceptsMaybeRefOrGetterforblocking/scrimand exposes them asReadonly<Ref<boolean>>on the ticket, so a reactiveblocking(e.g. a Dialog backing VDialog's reactivepersistent) propagates instead of freezing at registration.Dialog/AlertDialog/Portalnow pass them as getters.Type change:
StackTicket.blocking/scrimare nowReadonly<Ref<boolean>>(wereboolean) — read.value. Reads are internal to v0;register()still accepts plain booleans. -
#442
789c2e9Thanks @johnleider! - fix(useStack): don't share the fallback stack across SSR requests —useStack()fell back to a module-scoped singleton when no provider existed, so in a long-lived Node SSR process overlay tickets persisted across requests (z-index bleed + unbounded memory growth). Under SSR (!IN_BROWSER),getStackFallback()now returns a fresh ephemeralcreateStack()per call instead of the shared global; the browser singleton is unchanged. For coordinated per-app SSR z-index, usecreateStackPlugin(as the docs already advise). -
#588
237c90aThanks @johnleider! - fix(createValidation): stopisValidatingstickingtruewhen a silent validation interleaves an async one (#588) — triggering a silentvalidate()while a non-silent async validation was still in flight leftisValidatingstuck attrue(a permanent loading/validating state) until the next clean validation. The flag is now owned by the latest non-silent run and clears reliably.