Skip to content

Parity ​

This page shows the state of each Vase UI family against Base UI. A family is one folder of Base UI that Vase UI ports, and the column Component shows which families are components. A component that Base UI does not have is not a family. The site build makes this page from the parity folder of the repository, with the functions of pnpm parity:check. The build fails when that check fails.

Status: 38 of 38 components. The guarantee starts with the first full release.

Tracked commitDescribed asDateRelease
5aacdbbv1.9.0-149-g5aacdbb72026-11-101.9.0
FamilyComponentMatched commitSources portedCases matchedQueued changes
accordionYes5aacdbb 2026-11-1016 of 1646 of 470
alert-dialogYes5aacdbb 2026-11-106 of 610 of 100
autocompleteYes5aacdbb 2026-11-1012 of 12104 of 1070
avatarYes5aacdbb 2026-11-109 of 944 of 440
buttonYes5aacdbb 2026-11-103 of 39 of 90
checkboxYes5aacdbb 2026-11-108 of 8101 of 1060
checkbox-groupYes5aacdbb 2026-11-105 of 585 of 890
collapsibleYes5aacdbb 2026-11-1013 of 1353 of 550
comboboxYes5aacdbb 2026-11-1060 of 60730 of 7390
commonNo5aacdbb 2026-11-1033 of 6160 of 1750
context-menuYes5aacdbb 2026-11-109 of 928 of 320
csp-providerNo5aacdbb 2026-11-104 of 54 of 40
delay-groupNo5aacdbb 2026-11-101 of 16 of 60
dialogYes5aacdbb 2026-11-1024 of 24118 of 1240
direction-providerNo5aacdbb 2026-11-104 of 52 of 20
drawerYes5aacdbb 2026-11-1031 of 31275 of 2790
fieldYes5aacdbb 2026-11-1018 of 18164 of 1690
fieldsetYes5aacdbb 2026-11-106 of 610 of 110
filter-dropdownNo5aacdbb 2026-11-1013 of 1315 of 150
focusNo5aacdbb 2026-11-106 of 6113 of 1130
formYes5aacdbb 2026-11-104 of 436 of 360
handbook-animationNo5aacdbb 2026-11-100 of 00 of 00
handbook-formsNo5aacdbb 2026-11-100 of 00 of 00
inputYes5aacdbb 2026-11-103 of 30 of 00
interactionsNo5aacdbb 2026-11-1015 of 15194 of 1990
internalsNo5aacdbb 2026-11-1075 of 80248 of 2750
menuYes5aacdbb 2026-11-1076 of 76558 of 5720
menubarYes5aacdbb 2026-11-104 of 444 of 440
merge-propsNo5aacdbb 2026-11-102 of 230 of 300
meterYes5aacdbb 2026-11-108 of 825 of 250
navigation-menuYes5aacdbb 2026-11-1033 of 33122 of 1290
number-fieldYes5aacdbb 2026-11-1025 of 25473 of 4750
otp-fieldYes5aacdbb 2026-11-109 of 9159 of 1630
popoverYes5aacdbb 2026-11-1029 of 29160 of 1630
popupsNo5aacdbb 2026-11-1032 of 32264 of 2650
portalNo5aacdbb 2026-11-102 of 214 of 170
preview-cardYes5aacdbb 2026-11-1024 of 2459 of 590
progressYes5aacdbb 2026-11-1014 of 1425 of 250
radioYes5aacdbb 2026-11-108 of 818 of 190
radio-groupYes5aacdbb 2026-11-104 of 483 of 880
scroll-areaYes5aacdbb 2026-11-1022 of 2297 of 980
selectYes5aacdbb 2026-11-1040 of 40327 of 3320
separatorYes5aacdbb 2026-11-103 of 32 of 20
sliderYes5aacdbb 2026-11-1026 of 27235 of 2370
switchYes5aacdbb 2026-11-108 of 867 of 690
tabsYes5aacdbb 2026-11-1017 of 18138 of 1420
toastYes5aacdbb 2026-11-1036 of 36218 of 2240
toggleYes5aacdbb 2026-11-103 of 37 of 70
toggle-groupYes5aacdbb 2026-11-104 of 423 of 230
toolbarYes5aacdbb 2026-11-1016 of 1657 of 570
tooltipYes5aacdbb 2026-11-1024 of 24120 of 1210
treeNo5aacdbb 2026-11-103 of 36 of 60
unstable-use-media-queryNo5aacdbb 2026-11-101 of 12 of 40
use-renderNo5aacdbb 2026-11-102 of 214 of 140
utilsNo5aacdbb 2026-11-1028 of 3046 of 490
viewportNo5aacdbb 2026-11-105 of 513 of 130

Families ​

Each source file, test and API row of Base UI needs a counterpart in Vase UI, or an exception row. A row has a reason and one of four kinds:

  • replaced: another Vase UI test covers the thing. The row names that test.
  • not-applicable: the thing is for something that only React has. The kind also covers an upstream file that no Base UI component imports.
  • engine: the case does not run in one browser engine because of the browser. The row names the engine and links to a browser bug or an upstream issue.
  • waits-on: the thing waits for an upstream file or folder that Vase UI does not have yet. The row names that path. A row that names a source file waits for the file itself.

A function that returns a different type from the type that Base UI documents has a row with the Vase UI type and the reason.

accordion

Matches the Base UI commit 5aacdbb of 2026-11-10.

Queued changes: 0.

Vase UI rows with no upstream row: 17.

FilesTotalPortedReplacedNot applicableWaits on
Sources1616000
Type tests11000
TestsTotalMatchedReplacedNot applicableWaits onEngine ChromiumEngine FirefoxEngine WebKit
Cases4746100000
Suite calls55000000
APITotalMatchedExcepted
Entries11110
Prop rows30255

Exception rows: 6.

ThingKindReasonDetail
packages/react/src/accordion/panel/AccordionPanel.test.tsx, block "<Accordion.Panel /> > server-side rendering"replacedA server render runs in Node with no DOM. The case is in the test file that the Node project runs, with the same title. Test: packages/vue/src/accordion/panel/AccordionPanel.node.test.tsx
docs/src/app/(docs)/react/components/accordion/types.md, entry "Root", prop "loopFocus"not-applicableBase UI deprecated the prop, and it has no effect. parity/scope.json lists it as not ported.
docs/src/app/(docs)/react/components/accordion/types.md, entry "Root", prop "orientation"not-applicableBase UI deprecated the prop, and it does not change the keyboard. parity/scope.json lists it as not ported. The state keeps orientation with the default value of Base UI, vertical, so each part has data-orientation="vertical".
docs/src/app/(docs)/react/components/accordion/types.md, entry "Root", prop "keepMounted"not-applicableThe part must tell an absent keepMounted from keepMounted={false}, because only the explicit false gets a warning when hiddenUntilFound is set. A Boolean prop that is absent is false in Vue, so the declared default is undefined. The part uses false for an absent prop, which is the default that Base UI documents.
docs/src/app/(docs)/react/components/accordion/types.md, entry "Panel", prop "hiddenUntilFound"not-applicableAn absent hiddenUntilFound takes the value of Accordion.Root, and hiddenUntilFound={false} overrides it. A Boolean prop that is absent is false in Vue, so the declared default is undefined. With no value on the root, the part uses false, which is the default that Base UI documents.
docs/src/app/(docs)/react/components/accordion/types.md, entry "Panel", prop "keepMounted"not-applicableAn absent keepMounted takes the value of Accordion.Root, and only an explicit keepMounted={false} gets a warning when hiddenUntilFound is set. A Boolean prop that is absent is false in Vue, so the declared default is undefined. With no value on the root, the part uses false, which is the default that Base UI documents.

Additions to the Base UI API: 3.

EntryKindNameReason
TriggerpropdisabledThe part reads disabled for its state and for useButton, so it is a declared prop. Base UI reads it from the native attributes of the trigger, and types.md has no row for a native attribute.
TriggerpropidThe part reads id to replace an absent or empty id with the generated id, and to give it to the item for aria-labelledby of the panel. It is thus a declared prop. Base UI reads it from the native attributes of the trigger, and types.md has no row for a native attribute.
PanelpropidThe part reads id to give it to the item for aria-controls of the trigger, so it is a declared prop. Base UI reads it from the native attributes of the panel, and types.md has no row for a native attribute.

Return types that differ from Base UI: 0.

alert-dialog

Matches the Base UI commit 5aacdbb of 2026-11-10.

Queued changes: 0.

Vase UI rows with no upstream row: 8.

FilesTotalPortedReplacedNot applicableWaits on
Sources66000
Type tests11000
TestsTotalMatchedReplacedNot applicableWaits onEngine ChromiumEngine FirefoxEngine WebKit
Cases1010000000
Suite calls33000000
APITotalMatchedExcepted
Entries17170
Prop rows43430

Exception rows: 0.

Additions to the Base UI API: 4.

EntryKindNameReason
TriggerpropdisabledThe part gives disabled to Dialog.Trigger, which reads it for its state and for useButton, so it is a declared prop. Base UI reads it from the native attributes of the trigger, and types.md has no row for a native attribute.
TitlepropidThe part gives id to the root for aria-labelledby of the popup and follows a change of it, so it is a declared prop. Base UI reads it from the native attributes of the title, and types.md has no row for a native attribute.
DescriptionpropidThe part gives id to the root for aria-describedby of the popup and follows a change of it, so it is a declared prop. Base UI reads it from the native attributes of the description, and types.md has no row for a native attribute.
ClosepropdisabledThe part reads disabled for its state and for useButton, so it is a declared prop. Base UI reads it from the native attributes of the button, and types.md has no row for a native attribute.

Return types that differ from Base UI: 1.

EntryVase UI returnsReason
createHandleAlertDialogHandle<Payload>AlertDialog.Handle is the class AlertDialogHandle. The declaration of the function names the class, and Base UI documents the same class by its name in the namespace.

autocomplete

Matches the Base UI commit 5aacdbb of 2026-11-10.

Queued changes: 0.

Vase UI rows with no upstream row: 17.

FilesTotalPortedReplacedNot applicableWaits on
Sources1212000
Type tests11000
TestsTotalMatchedReplacedNot applicableWaits onEngine ChromiumEngine FirefoxEngine WebKit
Cases107104300000
Suite calls00000000
APITotalMatchedExcepted
Entries34340
Prop rows1211210

Exception rows: 3.

ThingKindReasonDetail
packages/react/src/autocomplete/root/AutocompleteRoot.test.tsx, case "<Autocomplete.Root /> > Form > server-renders only the inline input name for native FormData"replacedA server render runs in Node with no DOM. The case is in the test file that the Node project runs, with the same title. Test: packages/vue/src/autocomplete/root/AutocompleteRoot.node.test.tsx
packages/react/src/autocomplete/root/AutocompleteRoot.test.tsx, case "<Autocomplete.Root /> > Form > server-renders only the outside-popup input name for native FormData"replacedA server render runs in Node with no DOM. The case is in the test file that the Node project runs, with the same title. Test: packages/vue/src/autocomplete/root/AutocompleteRoot.node.test.tsx
packages/react/src/autocomplete/root/AutocompleteRoot.test.tsx, case "<Autocomplete.Root /> > Form > server-renders the default popup input value without a form name before hydration"replacedA server render runs in Node with no DOM. The case is in the test file that the Node project runs, with the same title. Test: packages/vue/src/autocomplete/root/AutocompleteRoot.node.test.tsx

Additions to the Base UI API: 3.

EntryKindNameReason
TriggerpropidThe part reads id to name its element and, while the input is inside the popup, to register its control, so it is a declared prop. Base UI reads it from the native attributes of the trigger, and types.md has no row for a native attribute.
ListslotitemThe slot renders each filtered item with { item, index }. It replaces the function child of the list in Base UI.
GroupLabelpropidThe part registers id with its group for aria-labelledby, so it is a declared prop. Base UI reads it from the native attributes of the label, and types.md has no row for a native attribute.

Return types that differ from Base UI: 2.

EntryVase UI returnsReason
useFilterFilterBase UI documents the return type as AutocompleteFilter. The composable returns Filter, and AutocompleteFilter is that type under another name.
useFilteredItemsComputedRef<T[]>setup runs one time, so a plain array does not follow a change of the filtered items. The composable thus returns a ComputedRef of the array.

avatar

Matches the Base UI commit 5aacdbb of 2026-11-10.

Queued changes: 0.

Vase UI rows with no upstream row: 3.

FilesTotalPortedReplacedNot applicableWaits on
Sources99000
Type tests11000
TestsTotalMatchedReplacedNot applicableWaits onEngine ChromiumEngine FirefoxEngine WebKit
Cases4444000000
Suite calls33000000
APITotalMatchedExcepted
Entries440
Prop rows12120

Exception rows: 0.

Additions to the Base UI API: 5.

EntryKindNameReason
ImagepropsrcThe part reads src to load the image before it renders the element, so it is a declared prop. Base UI reads it from the native attributes of the image, and types.md has no row for a native attribute.
ImagepropsrcsetThe part reads srcset to load the image before it renders the element, so it is a declared prop. Base UI reads it from the native attributes of the image, and types.md has no row for a native attribute.
ImagepropsizesThe part reads sizes to load the image before it renders the element, so it is a declared prop. Base UI reads it from the native attributes of the image, and types.md has no row for a native attribute.
ImagepropcrossoriginThe part reads crossorigin to load the image before it renders the element, so it is a declared prop. Base UI reads it from the native attributes of the image, and types.md has no row for a native attribute.
ImagepropreferrerpolicyThe part reads referrerpolicy to load the image before it renders the element, so it is a declared prop. Base UI reads it from the native attributes of the image, and types.md has no row for a native attribute.

Return types that differ from Base UI: 0.

button

Matches the Base UI commit 5aacdbb of 2026-11-10.

Queued changes: 0.

Vase UI rows with no upstream row: 4.

FilesTotalPortedReplacedNot applicableWaits on
Sources33000
Type tests11000
TestsTotalMatchedReplacedNot applicableWaits onEngine ChromiumEngine FirefoxEngine WebKit
Cases99000000
Suite calls11000000
APITotalMatchedExcepted
Entries220
Prop rows550

Exception rows: 0.

Additions to the Base UI API: 1.

EntryKindNameReason
ButtonpropdisabledThe part reads disabled for its state and for useButton, so it is a declared prop. Base UI reads it from the native attributes of the button, and types.md has no row for a native attribute.

Return types that differ from Base UI: 0.

checkbox

Matches the Base UI commit 5aacdbb of 2026-11-10.

Queued changes: 0.

Vase UI rows with no upstream row: 47.

FilesTotalPortedReplacedNot applicableWaits on
Sources88000
Type tests00000
TestsTotalMatchedReplacedNot applicableWaits onEngine ChromiumEngine FirefoxEngine WebKit
Cases106101050000
Suite calls33000000
APITotalMatchedExcepted
Entries440
Prop rows22220

Exception rows: 2.

ThingKindReasonDetail
packages/react/src/checkbox/root/CheckboxRoot.react17.test.tsxnot-applicableThe file tests the id paths for React 17. It mocks SafeReact, so that React has no useId. Vue useId gives the ids.
packages/react/src/checkbox/root/CheckboxRoot.test.tsx, case "<Checkbox.Root /> > prefers a render element's `aria-label` over an associated label"not-applicableThe case gives the aria-label as a prop of a React element in render. Base UI reads that prop with React.isValidElement. In Vue, an element with props of its own is the #render slot, and a part does not see an attribute that the slot adds. Base UI also does not see an attribute that a render function adds.

Additions to the Base UI API: 2.

EntryKindNameReason
RootpropariaLabelThe part reads aria-label to find out if a label names the checkbox, and $attrs is not reactive, so it is a declared prop. Base UI reads it from the native attributes of the element, and types.md has no row for a native attribute.
RootpropariaLabelledbyThe part reads aria-labelledby to find out if a label names the checkbox, and $attrs is not reactive, so it is a declared prop. Base UI reads it from the native attributes of the element, and types.md has no row for a native attribute.

Return types that differ from Base UI: 0.

checkbox-group

Matches the Base UI commit 5aacdbb of 2026-11-10.

Queued changes: 0.

Vase UI rows with no upstream row: 36.

FilesTotalPortedReplacedNot applicableWaits on
Sources55000
Type tests00000
TestsTotalMatchedReplacedNot applicableWaits onEngine ChromiumEngine FirefoxEngine WebKit
Cases8985400000
Suite calls11000000
APITotalMatchedExcepted
Entries220
Prop rows880

Exception rows: 4.

ThingKindReasonDetail
packages/react/src/checkbox-group/CheckboxGroup.test.tsx, case "<CheckboxGroup /> > Field.Label > keeps checkbox ids unique in a shared Field.Root during SSR (nativeButton=%s)"replacedA server render runs in Node with no DOM. The case is in the test file that the Node project runs, with the same title. Test: packages/vue/src/checkbox-group/CheckboxGroup.node.test.tsx
packages/react/src/checkbox-group/CheckboxGroup.test.tsx, case "<CheckboxGroup /> > Field.Label > associates Field.Label with a grouped Checkbox during SSR (nativeButton=$nativeButton, parent=$parent)"replacedA server render runs in Node with no DOM. The case is in the test file that the Node project runs, with the same title. Test: packages/vue/src/checkbox-group/CheckboxGroup.node.test.tsx
packages/react/src/checkbox-group/CheckboxGroup.test.tsx, case "<CheckboxGroup /> > Form > validates an inputless controlled group on change with validationMode=onChange"replacedThe case reads the second argument of validate, and it expects the field group there. Base UI keeps the fields of a page that has no form in a variable of the module. Vase UI keeps no such variable, so a field with no form sees no other field, and the argument is an empty object. The case "validates an inputless controlled group on change" in the block "a field with no form" has the same steps and asserts that argument. Test: packages/vue/src/checkbox-group/CheckboxGroup.test.tsx
packages/react/src/checkbox-group/CheckboxGroup.test.tsx, case "<CheckboxGroup /> > Form > validates an initially empty group through the imperative action"replacedThe case reads the second argument of validate, and it expects the field group there. Base UI keeps the fields of a page that has no form in a variable of the module. Vase UI keeps no such variable, so a field with no form sees no other field, and the argument is an empty object. The case "validates an initially empty group through the exposed validate" in the block "a field with no form" has the same steps and asserts that argument. Test: packages/vue/src/checkbox-group/CheckboxGroup.test.tsx

Additions to the Base UI API: 1.

EntryKindNameReason
CheckboxGrouppropidThe part reads id to register its control with the field, and $attrs is not reactive, so it is a declared prop. Base UI reads it from the native attributes of the element, and types.md has no row for a native attribute.

Return types that differ from Base UI: 0.

collapsible

Matches the Base UI commit 5aacdbb of 2026-11-10.

Queued changes: 0.

Vase UI rows with no upstream row: 13.

FilesTotalPortedReplacedNot applicableWaits on
Sources1313000
Type tests11000
TestsTotalMatchedReplacedNot applicableWaits onEngine ChromiumEngine FirefoxEngine WebKit
Cases5553200000
Suite calls33000000
APITotalMatchedExcepted
Entries770
Prop rows16151

Exception rows: 2.

ThingKindReasonDetail
packages/react/src/collapsible/panel/CollapsiblePanel.test.tsx, block "<Collapsible.Panel /> > server-side rendering"replacedA server render runs in Node with no DOM. The two cases are in the test file that the Node project runs, with the same titles. Test: packages/vue/src/collapsible/panel/CollapsiblePanel.node.test.tsx
docs/src/app/(docs)/react/components/collapsible/types.md, entry "Panel", prop "keepMounted"not-applicableThe part must tell an absent keepMounted from keepMounted={false}, because only the explicit false gets a warning when hiddenUntilFound is set. A Boolean prop that is absent is false in Vue, so the declared default is undefined. The part uses false for an absent prop, which is the default that Base UI documents.

Additions to the Base UI API: 2.

EntryKindNameReason
TriggerpropdisabledThe part reads disabled for its state and for useButton, so it is a declared prop. Base UI reads it from the native attributes of the trigger, and types.md has no row for a native attribute.
PanelpropidThe part reads id to give it to the root for aria-controls, so it is a declared prop. Base UI reads it from the native attributes of the panel, and types.md has no row for a native attribute.

Return types that differ from Base UI: 0.

combobox

Matches the Base UI commit 5aacdbb of 2026-11-10.

Queued changes: 0.

Vase UI rows with no upstream row: 158.

FilesTotalPortedReplacedNot applicableWaits on
Sources6060000
Type tests11000
TestsTotalMatchedReplacedNot applicableWaits onEngine ChromiumEngine FirefoxEngine WebKit
Cases739730540000
Suite calls2626000000
APITotalMatchedExcepted
Entries42420
Prop rows1441431

Exception rows: 10.

ThingKindReasonDetail
docs/src/app/(docs)/react/components/combobox/types.md, entry "Root", prop "multiple"not-applicableThe row gives the default false. The prop has no declared default, because withDefaults refuses a default for a prop of the generic type Multiple & boolean (TS2322). Vue gives an absent Boolean prop the value false, and the JSDoc has @default false for the API reference.
packages/react/src/combobox/chips/ComboboxChips.test.tsx, case "<Combobox.Chips /> > does not focus the input when pressing content in a nested React portal"not-applicableReact sends the press of a portal up the React tree, so the chips get it. A Vue press goes up the DOM only, and a Teleport puts its content outside the chips. The chips thus get no such press.
packages/react/src/combobox/input-group/ComboboxInputGroup.test.tsx, case "<Combobox.InputGroup /> > does not focus the input when pressing content in a nested React portal"not-applicableReact sends the press of a portal up the React tree, so the input group gets it. A Vue press goes up the DOM only, and a Teleport puts its content outside the input group. The group thus gets no such press.
packages/react/src/combobox/items/createItems.test.tsx, case "Combobox.createItems > integration > resolves a server-rendered defaultValue label from the external window"replacedA server render runs in Node with no DOM. The case is in the test file that the Node project runs, with the same title. Test: packages/vue/src/combobox/items/createItems.node.test.tsx
packages/react/src/combobox/label/ComboboxLabel.test.tsx, case "<Combobox.Label /> > does not run the development warning in production"replacedThe case needs a production build. Vitest sets process.env.NODE_ENV when it transforms a file for a browser, so only the Node project can change it. Test: packages/vue/src/combobox/label/ComboboxLabel.node.test.tsx
packages/react/src/combobox/root/ComboboxRoot.test.tsx, case "<Combobox.Root /> > server-side rendering > sets combobox aria attributes on the input"replacedA server render runs in Node with no DOM. The case is in the test file that the Node project runs, with the same title. Test: packages/vue/src/combobox/root/ComboboxRoot.node.test.tsx
packages/react/src/combobox/root/ComboboxRoot.test.tsx, case "<Combobox.Root /> > server-side rendering > sets combobox aria attributes on the trigger when input is inside popup"replacedA server render runs in Node with no DOM. The case is in the test file that the Node project runs, with the same title. Test: packages/vue/src/combobox/root/ComboboxRoot.node.test.tsx
packages/react/src/combobox/root/ComboboxRoot.test.tsx, case "<Combobox.Root /> > server-side rendering > does not link Combobox.Label to trigger before hydration"replacedThe case renders on a server only. Vase UI links the label in the server HTML (VUE-51). The case "VUE-51: names the trigger with a label that comes before it" asserts that link. The case "names the trigger that comes before it" of ComboboxLabel.node.test.tsx asserts it for a label after the trigger. Test: packages/vue/src/combobox/root/ComboboxRoot.node.test.tsx
packages/react/src/combobox/root/ComboboxRoot.test.tsx, case "<Combobox.Root /> > does not dismiss when pressing portalled content inside the popup but outside the list"not-applicableReact sends the press of a portal up the React tree, so the popup knows that the press is inside it. A Vue press goes up the DOM only, and a Teleport puts its content outside the popup. The press is thus a press outside the popup, and it closes the popup.
packages/react/src/combobox/root/ComboboxRoot.test.tsx, case "<Combobox.Root /> > does not navigate the list with arrow keys from portalled controls inside the popup"not-applicableReact sends the key of a portal up the React tree, so the list could get it. A Vue key goes up the DOM only, and a Teleport puts its content outside the list. The list thus gets no such key.

Additions to the Base UI API: 4.

EntryKindNameReason
TriggerpropidThe part reads id to name its element. While the input is inside the popup, the part also registers id as the id of the control of the field, so it is a declared prop. Base UI reads id from the native attributes of the trigger, and types.md has no row for a native attribute.
ListslotitemThe slot renders each filtered item with { item, index }. It replaces the function child of the list in Base UI.
GroupLabelpropidThe part gives id to the group for aria-labelledby and follows a change of it, so it is a declared prop. Base UI reads it from the native attributes of the group label, and types.md has no row for a native attribute.
ChipRemovepropdisabledThe part reads disabled and disables its button when the prop or the root says so, so it is a declared prop. Base UI reads it from the native attributes of the button, and types.md has no row for a native attribute.

Return types that differ from Base UI: 3.

EntryVase UI returnsReason
createItemsComboboxItemCollection<Item, Value>Base UI documents the second type argument of the result as ComboboxPrimitiveValue. The function is generic in Value, as the Base UI source is, and the result has the type argument Value of the call.
useFilterFilterBase UI documents the return type as ComboboxFilter. The composable returns Filter, and ComboboxFilter is that type under another name.
useFilteredItemsComputedRef<T[]>setup runs one time, so a plain array does not follow a change of the filtered items. The composable thus returns a ComputedRef of the array.

common

Matches the Base UI commit 5aacdbb of 2026-11-10.

Queued changes: 0.

Vase UI rows with no upstream row: 4.

FilesTotalPortedReplacedNot applicableWaits on
Sources61330280
Type tests62040
TestsTotalMatchedReplacedNot applicableWaits onEngine ChromiumEngine FirefoxEngine WebKit
Cases1756021130000
Suite calls00000000

Exception rows: 48.

ThingKindReasonDetail
packages/utils/src/fastHooks.tsnot-applicableThe file joins the store subscriptions of one React component. A Vue component tracks each reactive read, so it needs no such wrapper.
packages/utils/src/store/ReactStore.tsnot-applicableThe methods of the class call React hooks. ReactiveStore of packages/vue/src/utils/popups/ReactiveStore.ts holds the state, the context and the selectors on Vue reactivity.
packages/utils/src/store/Store.tsnot-applicableThe class keeps a list of subscribers and gives each one the new state object. A write to shallowReactive state tells the readers, so ReactiveStore of packages/vue/src/utils/popups/ReactiveStore.ts has no such list.
packages/utils/src/store/index.tsnot-applicableThe file exports the store classes and hooks for React. The store of Vase UI is in packages/vue/src/utils/popups/ReactiveStore.ts.
packages/utils/src/store/useStore.tsnot-applicableThe hook subscribes a React component to a store through useSyncExternalStore. A Vue computed that calls select of the store does this work.
packages/utils/src/lruMemoize.tsnot-applicableNo Base UI component imports the selector factories, and Vue computed does this work. lruMemoize is a re-export of reselect that only createSelectorMemoized uses.
packages/utils/src/store/createSelector.tsnot-applicableNo Base UI component imports the selector factories, and Vue computed does this work. lruMemoize is a re-export of reselect that only createSelectorMemoized uses.
packages/utils/src/store/createSelectorMemoized.tsnot-applicableNo Base UI component imports the selector factories, and Vue computed does this work. lruMemoize is a re-export of reselect that only createSelectorMemoized uses.
packages/utils/src/store/StoreInspector.tsxnot-applicableA React development panel. No component imports it.
packages/utils/src/getReactElementRef.tsnot-applicableThe file exists only to support old React versions.
packages/utils/src/inertValue.tsnot-applicableThe file exists only to support old React versions.
packages/utils/src/reactVersion.tsnot-applicableThe file exists only to support old React versions.
packages/utils/src/safeReact.tsnot-applicableThe file exists only to support old React versions.
packages/utils/src/useStableCallback.tsnot-applicableVue runs setup one time, so a function made there keeps its identity. It reads the current state when it runs.
packages/utils/src/useIsoLayoutEffect.tsnot-applicableVue has onMounted, onBeforeUnmount and watch with flush: 'post'. The two hooks do not run on a server. A watch callback with flush: 'post' runs on a server only when it has immediate.
packages/utils/src/useOnFirstRender.tsnot-applicableVue runs setup one time. A value made there is made one time, and code there runs one time.
packages/utils/src/useRefWithInit.tsnot-applicableVue runs setup one time. A value made there is made one time, and code there runs one time.
packages/utils/src/useValueAsRef.tsnot-applicableA getter or a ref gives the current value. A read outside an effect adds no dependency.
packages/utils/src/useOnMount.tsnot-applicableonMounted and onScopeDispose do this work.
packages/utils/src/useForcedRerendering.tsnot-applicableA change of reactive state renders the component again, and triggerRef forces it.
packages/utils/src/useMergedRefs.tsnot-applicableA part has one ref setter function, which gives the element to each internal user. Vue has no ref objects to merge.
packages/utils/src/usePreviousValue.tsnot-applicableA Vue watch callback gets the old value of its source, with the same Object.is comparison.
packages/utils/src/useId.tsnot-applicableThe file wraps React useId and holds a fallback for React 17. Vue useId gives the ids.
packages/utils/src/fastObjectShallowCompare.tsnot-applicableNo Base UI component imports the file at the matched commit.
packages/utils/src/useIdleCallback.tsnot-applicableNo Base UI component imports the file at the matched commit.
packages/utils/src/isMouseWithinBounds.tsnot-applicableBase UI marks it as deprecated, and no component imports it. The components use isMouseWithinBounds of packages/react/src/utils/getPseudoElementBounds.ts.
packages/utils/src/isHTMLElement.tsnot-applicableA re-export of @floating-ui/utils/dom. Base UI components import isHTMLElement from that package, and Vase UI does the same.
packages/utils/src/formatErrorMessage.tsnot-applicableOnly code that the Base UI build generates calls it: a Babel plugin replaces each error message with a code. The Vase UI build keeps the full messages.
packages/utils/src/store/Store.test.tsnot-applicableThe cases test the subscriber list of the Store class and Store.create. packages/vue/src/utils/popups/ReactiveStore.test.tsx tests the writes of the Vue store.
packages/utils/src/store/Store.spec.tsnot-applicableIt tests the type of Store.create, which the Vue store does not have.
packages/utils/src/store/ReactStore.test.tsxnot-applicableThe cases test the React hooks of ReactStore and its observe method. A Vue computed and a watch do this work.
packages/utils/src/store/ReactStore.spec.tsnot-applicableIt tests the types of the React hooks of ReactStore. packages/vue/src/utils/popups/ReactiveStore.spec.ts tests the types of select, set and update.
packages/utils/src/store/createSelector.test.tsnot-applicableNo Base UI component imports the selector factories. Vue computed does this work.
packages/utils/src/store/createSelector.spec.tsnot-applicableNo Base UI component imports the selector factories. Vue computed does this work.
packages/utils/src/store/createSelectorMemoized.test.tsnot-applicableNo Base UI component imports the selector factories. Vue computed does this work.
packages/utils/src/store/createSelectorMemoized.spec.tsnot-applicableNo Base UI component imports the selector factories. Vue computed does this work.
packages/utils/src/store/StoreInspector.test.tsxnot-applicableIt tests a React development panel that no component imports.
packages/utils/src/getReactElementRef.test.tsxnot-applicableIt tests a helper that reads the ref of a React element in React 17, 18 and 19.
packages/utils/src/useId.test.tsxnot-applicableIt tests a wrapper of React useId. Vue useId gives the ids.
packages/utils/src/useId.react17.test.tsxnot-applicableIt tests the id fallback for React 17.
packages/utils/src/useIdleCallback.test.tsxnot-applicableNo Base UI component imports useIdleCallback at the matched commit.
packages/utils/src/useIdleCallback.fallback.test.tsnot-applicableNo Base UI component imports useIdleCallback at the matched commit.
packages/utils/src/useMergedRefs.test.tsxnot-applicableIt tests the merge of React refs. A Vue part has one ref setter function.
packages/utils/src/usePreviousValue.test.tsxnot-applicableIt tests a React state hook. A Vue watch callback gets the old value of its source, with the same Object.is comparison.
packages/utils/src/formatErrorMessage.test.tsnot-applicableOnly code that the Base UI build generates calls formatErrorMessage. The Vase UI build keeps the full messages.
packages/utils/src/hydration.test.tsx, block "hydration > React 17 paths"not-applicableThe cases test the code path for React 17.
packages/utils/src/hydration.test.tsx, case "hydration > useIsHydrated > does not report hydrated while rendering on the server"replacedA server render runs in Node with no DOM. The case is in the test file that the Node project runs, with the same title. Test: packages/vue/src/common/hydration.node.test.tsx
packages/utils/src/hydration.test.tsx, case "hydration > useIsHydrating > reports hydrating while rendering on the server"replacedA server render runs in Node with no DOM. The case is in the test file that the Node project runs, with the same title. Test: packages/vue/src/common/hydration.node.test.tsx

Additions to the Base UI API: 0.

Return types that differ from Base UI: 0.

context-menu

Matches the Base UI commit 5aacdbb of 2026-11-10.

Queued changes: 0.

Vase UI rows with no upstream row: 34.

FilesTotalPortedReplacedNot applicableWaits on
Sources99000
Type tests00000
TestsTotalMatchedReplacedNot applicableWaits onEngine ChromiumEngine FirefoxEngine WebKit
Cases3228004000
Suite calls11000000
APITotalMatchedExcepted
Entries33330
Prop rows1261251

Exception rows: 5.

ThingKindReasonDetail
packages/react/src/context-menu/root/ContextMenuRoot.non-mac.test.tsxwaits-onThe other rows of this family that wait on parts of Menu name this file as their target. The file thus stays absent until the last of those parts exists. Its case needs only ContextMenu.Item.Waits on: packages/react/src/context-menu/root/ContextMenuRoot.non-mac.test.tsx
packages/react/src/context-menu/root/ContextMenuRoot.test.tsx, case "<ContextMenu.Root /> > returns focus to the focused surface when closing with Shift+Tab"waits-onThe case closes the menu with the Tab key. The list navigation of the menu root closes a menu for Tab and for Shift+Tab, and it gives the focus back to the trigger. Menu.Root has no list navigation yet, so the key does not close the menu.Waits on: packages/react/src/context-menu/root/ContextMenuRoot.non-mac.test.tsx
packages/react/src/context-menu/root/ContextMenuRoot.test.tsx, case "<ContextMenu.Root /> > returns focus to the focused surface when closing with Tab"waits-onThe case closes the menu with the Tab key. The list navigation of the menu root closes a menu for Tab and for Shift+Tab, and it gives the focus back to the trigger. Menu.Root has no list navigation yet, so the key does not close the menu.Waits on: packages/react/src/context-menu/root/ContextMenuRoot.non-mac.test.tsx
packages/react/src/context-menu/trigger/ContextMenuTrigger.test.tsx, case "<ContextMenu.Trigger /> > keeps the root menu open when the context-menu gesture ends in a portaled submenu"waits-onThe trigger lacks the check of the root owner id at the mouseup, which needs findRootOwnerId of Menu. Vase UI does not have that file yet, so a mouseup in a submenu closes the menu.Waits on: packages/react/src/context-menu/root/ContextMenuRoot.non-mac.test.tsx
docs/src/app/(docs)/react/components/context-menu/types.md, entry "Positioner", prop "side"not-applicableThe row gives the default 'bottom'. The part has no Vue default: a prop that is absent lets Menu.Positioner take 'bottom' for a root context menu and 'inline-end' for a submenu, as in Base UI. Only an absent side gives a root context menu the offsets -5 and 2. With a Vue default, a submenu opens below its trigger and a root context menu loses those offsets.

Additions to the Base UI API: 7.

EntryKindNameReason
PopuppropidThe part replaces an absent id with a generated id and gives the id to the root, which the trigger names in aria-controls. Base UI declares id as a prop with the tag @ignore, so types.md has no row for it.
ItempropidThe part replaces an absent id with a generated id and renders it on the item. Base UI declares id as a prop with the tag @ignore, so types.md has no row for it.
LinkItempropidThe part replaces an absent id with a generated id and renders it on the link. Base UI declares id as a prop with the tag @ignore, so types.md has no row for it.
SubmenuTriggerpropidThe part replaces an absent id with a generated id and registers the trigger in the store of the submenu with it. Base UI declares id as a prop with the tag @ignore, so types.md has no row for it.
GroupLabelpropidThe part replaces an absent id with a generated id and gives it to the group for aria-labelledby. It is thus a declared prop. Base UI reads it from the native attributes of the label, and types.md has no row for a native attribute.
RadioItempropidThe part replaces an absent id with a generated id and renders it on the item. Base UI declares id as a prop with the tag @ignore, so types.md has no row for it.
CheckboxItempropidThe part replaces an absent id with a generated id and renders it on the item. Base UI declares id as a prop with the tag @ignore, so types.md has no row for it.

Return types that differ from Base UI: 0.

csp-provider

Matches the Base UI commit 5aacdbb of 2026-11-10.

Queued changes: 0.

Vase UI rows with no upstream row: 4.

FilesTotalPortedReplacedNot applicableWaits on
Sources54010
Type tests00000
TestsTotalMatchedReplacedNot applicableWaits onEngine ChromiumEngine FirefoxEngine WebKit
Cases44000000
Suite calls00000000
APITotalMatchedExcepted
Entries110
Prop rows330

Exception rows: 1.

ThingKindReasonDetail
packages/react/src/internals/csp-context/index.tsnot-applicableNo Base UI component imports the file. It is the module of the package entry ./internals/csp-context, and Vase UI has no entry point for an internal module.

Additions to the Base UI API: 0.

Return types that differ from Base UI: 0.

delay-group

Matches the Base UI commit 5aacdbb of 2026-11-10.

Queued changes: 0.

Vase UI rows with no upstream row: 17.

FilesTotalPortedReplacedNot applicableWaits on
Sources11000
Type tests00000
TestsTotalMatchedReplacedNot applicableWaits onEngine ChromiumEngine FirefoxEngine WebKit
Cases66000000
Suite calls00000000

Exception rows: 0.

Additions to the Base UI API: 0.

Return types that differ from Base UI: 0.

dialog

Matches the Base UI commit 5aacdbb of 2026-11-10.

Queued changes: 0.

Vase UI rows with no upstream row: 73.

FilesTotalPortedReplacedNot applicableWaits on
Sources2424000
Type tests11000
TestsTotalMatchedReplacedNot applicableWaits onEngine ChromiumEngine FirefoxEngine WebKit
Cases124118420000
Suite calls1313000000
APITotalMatchedExcepted
Entries17170
Prop rows45450

Exception rows: 6.

ThingKindReasonDetail
packages/react/src/dialog/popup/DialogPopup.test.tsx, case "<Dialog.Popup /> > prop: finalFocus > respects finalFocus when initialFocus points outside the popup"replacedWith modal set to true, the elements outside the popup are inert (BUG-4678), so initialFocus cannot focus an element outside the popup. The case BUG-4678: keeps the initial focus off an inert element, and returns the focus to $name tests this, and the return of the focus. Test: packages/vue/src/dialog/popup/DialogPopup.test.tsx
packages/react/src/dialog/popup/DialogPopup.test.tsx, case "<Dialog.Popup /> > prop: finalFocus > moves final focus to trigger if initialFocus points outside the popup and finalFocus is not specified"replacedWith modal set to true, the elements outside the popup are inert (BUG-4678), so initialFocus cannot focus an element outside the popup. The case BUG-4678: keeps the initial focus off an inert element, and returns the focus to $name tests this, and the return of the focus. Test: packages/vue/src/dialog/popup/DialogPopup.test.tsx
packages/react/src/dialog/portal/DialogPortal.test.tsx, case "<Dialog.Portal /> > Suspense integration > should not throw "Maximum update depth exceeded" when Suspense boundary is outside Portal"not-applicableThe case guards a render loop of React (issue 3695) while a Suspense boundary outside the portal waits for a lazy component in the popup. The portal of Vase UI renders its content after the mount, so a Vue <Suspense> around it does not wait for that content and shows no fallback.
packages/react/src/dialog/root/DialogRoot.detached-triggers.test.tsx, case "<Dialog.Root /> > handle-backed root ownership > does not warn for a detached payload open in production"replacedThe case needs a production build. Vitest sets process.env.NODE_ENV when it transforms a file for a browser, so only the Node project can change it. The case ignores openWithPayload() with no root and gives no warning in a production build tests the same. Test: packages/vue/src/dialog/root/DialogRoot.node.test.tsx
packages/react/src/dialog/root/DialogRoot.detached-triggers.test.tsx, case "<Dialog.Root /> > handle-backed root ownership > multiple roots sharing one handle > keeps the root attached through Strict Mode effect replay"not-applicableThe case tests React Strict Mode. Vue has no Strict Mode.
packages/react/src/dialog/root/DialogRoot.test.tsx, case "<Dialog.Root /> > closes a popover opened during a nested dialog, not the parent, on Escape after the nested dialog closes"replacedThe case expects the focus on <body> after the nested dialog closes. Vase UI moves it into the parent popup (BUG-6037), so Escape there closes the parent. The case BUG-6037: on Escape after a nested dialog closes, closes $name tests Escape with that focus, and with no focus in a popup, where the popover closes as in Base UI. Test: packages/vue/src/dialog/root/DialogRoot.test.tsx

Additions to the Base UI API: 4.

EntryKindNameReason
TriggerpropdisabledThe part reads disabled for its state and for useButton, so it is a declared prop. Base UI reads it from the native attributes of the trigger, and types.md has no row for a native attribute.
TitlepropidThe part reads id to register it with the root for aria-labelledby of the popup, so it is a declared prop. Base UI reads it from the native attributes of the title, and types.md has no row for a native attribute.
DescriptionpropidThe part reads id to register it with the root for aria-describedby of the popup, so it is a declared prop. Base UI reads it from the native attributes of the description, and types.md has no row for a native attribute.
ClosepropdisabledThe part reads disabled for its state and for useButton, so it is a declared prop. Base UI reads it from the native attributes of the button, and types.md has no row for a native attribute.

Return types that differ from Base UI: 1.

EntryVase UI returnsReason
createHandleDialogHandle<Payload>Dialog.Handle is the class DialogHandle. The declaration of the function names the class, and Base UI documents the same class by its name in the namespace.

direction-provider

Matches the Base UI commit 5aacdbb of 2026-11-10.

Queued changes: 0.

Vase UI rows with no upstream row: 0.

FilesTotalPortedReplacedNot applicableWaits on
Sources54010
Type tests11000
TestsTotalMatchedReplacedNot applicableWaits onEngine ChromiumEngine FirefoxEngine WebKit
Cases22000000
Suite calls00000000
APITotalMatchedExcepted
Entries220
Prop rows220

Exception rows: 1.

ThingKindReasonDetail
packages/react/src/internals/direction-context/index.tsnot-applicableNo Base UI component imports the file. It is the module of the package entry ./internals/direction-context, and Vase UI has no entry point for an internal module.

Additions to the Base UI API: 0.

Return types that differ from Base UI: 1.

EntryVase UI returnsReason
useDirectionComputedRef<TextDirection>setup runs one time, so a plain value does not follow a change of the provider. The composable returns a ComputedRef of the direction.

drawer

Matches the Base UI commit 5aacdbb of 2026-11-10.

Queued changes: 0.

Vase UI rows with no upstream row: 44.

FilesTotalPortedReplacedNot applicableWaits on
Sources3131000
Type tests11000
TestsTotalMatchedReplacedNot applicableWaits onEngine ChromiumEngine FirefoxEngine WebKit
Cases279275130000
Suite calls44000000
APITotalMatchedExcepted
Entries26260
Prop rows67670

Exception rows: 4.

ThingKindReasonDetail
packages/react/src/drawer/popup/DrawerPopup.test.tsx, case "<Drawer.Popup /> > warns without relying on React owner-stack support"not-applicableThe case mocks SafeReact.captureOwnerStack, which only React has. The warning of Drawer.Popup has no owner stack.
packages/react/src/drawer/provider/DrawerProvider.test.tsx, case "<Drawer.Provider /> > releases closed drawers once they are removed"replacedThe case forces a garbage collection through node:v8, so Base UI runs it only in jsdom. A browser has no node:v8. The case is in the test file that the Node project runs, with the same title. It reads the context of the provider from a server render. Test: packages/vue/src/drawer/provider/DrawerProvider.node.test.tsx
packages/react/src/drawer/swipe-area/DrawerSwipeArea.test.tsx, case "<Drawer.SwipeArea /> > works before a generated swipe area id is available"not-applicableThe case mocks useId to give undefined at first, as in React 17. useVaseUiId gives an id in setup, so the swipe area has its id in its first render.
packages/react/src/drawer/swipe-area/DrawerSwipeArea.test.tsx, case "<Drawer.SwipeArea /> > registers the swipe area once a generated id becomes available"not-applicableThe case mocks useId to give undefined at first, as in React 17. useVaseUiId gives an id in setup, so the swipe area has its id in its first render.

Additions to the Base UI API: 5.

EntryKindNameReason
TriggerpropdisabledThe part gives disabled to Dialog.Trigger, which reads it for its state and for useButton, so it is a declared prop. Base UI reads it from the native attributes of the trigger, and types.md has no row for a native attribute.
SwipeAreapropidThe part reads id to register the swipe area as a trigger in the store of the drawer, and follows a change of it, so it is a declared prop. Base UI reads it from the native attributes of the swipe area, and types.md has no row for a native attribute.
TitlepropidDrawer.Title is Dialog.Title. The part gives id to the root for aria-labelledby and follows a change of it, so it is a declared prop. Base UI reads it from the native attributes of the title, and types.md has no row for a native attribute.
DescriptionpropidDrawer.Description is Dialog.Description. The part gives id to the root for aria-describedby and follows a change of it, so it is a declared prop. Base UI reads it from the native attributes of the description, and types.md has no row for a native attribute.
ClosepropdisabledDrawer.Close is Dialog.Close. The part reads disabled for its state and for useButton, so it is a declared prop. Base UI reads it from the native attributes of the button, and types.md has no row for a native attribute.

Return types that differ from Base UI: 1.

EntryVase UI returnsReason
createHandleDrawerHandle<Payload>Drawer.Handle is the class DrawerHandle. The declaration of the function names the class, and Base UI documents the same class by its name in the namespace.

field

Matches the Base UI commit 5aacdbb of 2026-11-10.

Queued changes: 0.

Vase UI rows with no upstream row: 49.

FilesTotalPortedReplacedNot applicableWaits on
Sources1818000
Type tests11000
TestsTotalMatchedReplacedNot applicableWaits onEngine ChromiumEngine FirefoxEngine WebKit
Cases169164140000
Suite calls66000000
APITotalMatchedExcepted
Entries13130
Prop rows33312

Exception rows: 4.

ThingKindReasonDetail
packages/react/src/field/root/FieldRoot.react17.test.tsxnot-applicableThe file tests the paths for React 17. It mocks SafeReact, so that React has no useId and no captureOwnerStack. Vue useId gives the ids, and Vue has no owner stack.
packages/react/src/field/root/FieldRoot.test.tsx, case "<Field.Root /> > does not set `aria-labelledby` during SSR when Field.Label is absent"replacedA server render with no hydrate() runs in Node with no DOM. The case with the same title renders a select in a field with no label, and asserts that the server HTML of the trigger has no aria-labelledby. Test: packages/vue/src/field/root/FieldRoot.node.test.tsx
docs/src/app/(docs)/react/components/field/types.md, entry "Root", prop "actionsRef"not-applicableA React ref prop. The part exposes validate(), and the case "validates the field when the validate method is called" tests it. pnpm parity:check cannot read that member, because vue-component-meta leaves out an exposed member that has the name of a prop, and validate is also a prop.
docs/src/app/(docs)/react/components/field/types.md, entry "Root", prop "validationMode"not-applicableThe row gives the default 'onSubmit'. The part has no Vue default: a prop that is absent takes the validationMode of the form, and 'onSubmit' with no form, as in Base UI. With a Vue default, the part cannot find out that the prop is absent.

Additions to the Base UI API: 8.

EntryKindNameReason
ControlpropvalueThe part reads value to find out that it is controlled, so it is a declared prop. Base UI reads it from the native attributes of the input, and types.md has no row for a native attribute.
Controlemitupdate:valueThe part has the prop value, so v-model:value needs this emit. types.md has no row value, so the check expects no such emit.
ControlpropidThe part gives id to the labelable provider and follows a change of it, so it is a declared prop. Base UI reads it from the native attributes of the input.
ControlpropnameThe part registers name with the field and follows a change of it, so it is a declared prop. Base UI reads it from the native attributes of the input.
ControlpropdisabledThe part reads disabled for the state and for the registration, so it is a declared prop. Base UI reads it from the native attributes of the input.
ErrorpropidThe part gives id to the labelable provider as the id of a message and follows a change of it, so it is a declared prop. Base UI reads it from the native attributes of the div.
LabelpropidThe part gives id to the labelable provider as the id of a label and follows a change of it, so it is a declared prop. Base UI reads it from the native attributes of the label.
DescriptionpropidThe part gives id to the labelable provider as the id of a message and follows a change of it, so it is a declared prop. Base UI reads it from the native attributes of the p.

Return types that differ from Base UI: 0.

fieldset

Matches the Base UI commit 5aacdbb of 2026-11-10.

Queued changes: 0.

Vase UI rows with no upstream row: 11.

FilesTotalPortedReplacedNot applicableWaits on
Sources66000
Type tests00000
TestsTotalMatchedReplacedNot applicableWaits onEngine ChromiumEngine FirefoxEngine WebKit
Cases1110100000
Suite calls22000000
APITotalMatchedExcepted
Entries330
Prop rows660

Exception rows: 1.

ThingKindReasonDetail
packages/react/src/fieldset/legend/FieldsetLegend.test.tsx, case "<Fieldset.Legend /> > does not set `aria-labelledby` during SSR when legend is absent"replacedA server render with no hydrate() runs in Node with no DOM. The result differs from Base UI on purpose. A root that the consumer does not name assumes a legend until it is mounted, so the server HTML points at the generated id. An aria-labelledby with no valid IDREF gives no name (step 2B of https://www.w3.org/TR/accname-1.2/#computation-steps), so aria-label and the native name still apply. A root that has a non-blank aria-label or an aria-labelledby of the consumer has no generated id in the server HTML. The case "renders the generated id in the aria-labelledby of a root that has no legend" asserts the server HTML. The case "renders no aria-labelledby of its own on a root that the consumer names: $name" asserts that a named root has no generated id. The case "has no aria-labelledby when it has no legend" in FieldsetRoot.test.tsx asserts that the mounted root has none. Test: packages/vue/src/fieldset/legend/FieldsetLegend.node.test.tsx

Additions to the Base UI API: 2.

EntryKindNameReason
RootpropdisabledThe part reads disabled for the state and the context, so it is a declared prop. Base UI reads it from the native attributes of the root, and types.md has no row for a native attribute.
LegendpropidThe part reads id to give it to the root for aria-labelledby, so it is a declared prop. Base UI reads it from the native attributes of the legend, and types.md has no row for a native attribute.

Return types that differ from Base UI: 0.

filter-dropdown

Matches the Base UI commit 5aacdbb of 2026-11-10.

Queued changes: 0.

Vase UI rows with no upstream row: 4.

FilesTotalPortedReplacedNot applicableWaits on
Sources1313000
Type tests00000
TestsTotalMatchedReplacedNot applicableWaits onEngine ChromiumEngine FirefoxEngine WebKit
Cases1515000000
Suite calls11000000

Exception rows: 0.

Additions to the Base UI API: 0.

Return types that differ from Base UI: 0.

focus

Matches the Base UI commit 5aacdbb of 2026-11-10.

Queued changes: 0.

Vase UI rows with no upstream row: 91.

FilesTotalPortedReplacedNot applicableWaits on
Sources66000
Type tests00000
TestsTotalMatchedReplacedNot applicableWaits onEngine ChromiumEngine FirefoxEngine WebKit
Cases113113000000
Suite calls00000000

Exception rows: 0.

Additions to the Base UI API: 0.

Return types that differ from Base UI: 0.

form

Matches the Base UI commit 5aacdbb of 2026-11-10.

Queued changes: 0.

Vase UI rows with no upstream row: 32.

FilesTotalPortedReplacedNot applicableWaits on
Sources44000
Type tests11000
TestsTotalMatchedReplacedNot applicableWaits onEngine ChromiumEngine FirefoxEngine WebKit
Cases3636000000
Suite calls11000000
APITotalMatchedExcepted
Entries110
Prop rows770

Exception rows: 0.

Additions to the Base UI API: 3.

EntryKindNameReason
FormemitsubmitBase UI calls the native onSubmit of the consumer after its validation. In Vue, a native listener in the attributes runs before the part, so the part emits submit after its validation. types.md has no row for a native listener.
FormproponFormSubmitThe part must know that a formSubmit listener exists before it prevents the native submit. Vue gives a listener to a declared prop with that name, and the emit formSubmit still calls it. The row onFormSubmit of types.md maps to the emit.
FormproponFormSubmitOnceA template gives this key to a listener that it binds with @form-submit.once. The part reads it for the same reason as onFormSubmit. The emit formSubmit still calls the listener one time.

Return types that differ from Base UI: 0.

handbook-animation

Matches the Base UI commit 5aacdbb of 2026-11-10.

Queued changes: 0.

Vase UI rows with no upstream row: 0.

FilesTotalPortedReplacedNot applicableWaits on
Sources00000
Type tests00000
TestsTotalMatchedReplacedNot applicableWaits onEngine ChromiumEngine FirefoxEngine WebKit
Cases00000000
Suite calls00000000

Exception rows: 0.

Additions to the Base UI API: 0.

Return types that differ from Base UI: 0.

handbook-forms

Matches the Base UI commit 5aacdbb of 2026-11-10.

Queued changes: 0.

Vase UI rows with no upstream row: 0.

FilesTotalPortedReplacedNot applicableWaits on
Sources00000
Type tests00000
TestsTotalMatchedReplacedNot applicableWaits onEngine ChromiumEngine FirefoxEngine WebKit
Cases00000000
Suite calls00000000

Exception rows: 0.

Additions to the Base UI API: 0.

Return types that differ from Base UI: 0.

input

Matches the Base UI commit 5aacdbb of 2026-11-10.

Queued changes: 0.

Vase UI rows with no upstream row: 6.

FilesTotalPortedReplacedNot applicableWaits on
Sources33000
Type tests11000
TestsTotalMatchedReplacedNot applicableWaits onEngine ChromiumEngine FirefoxEngine WebKit
Cases00000000
Suite calls11000000
APITotalMatchedExcepted
Entries220
Prop rows660

Exception rows: 0.

Additions to the Base UI API: 1.

EntryKindNameReason
InputpropdisabledThe part gives its attributes to Field.Control, which declares disabled as a Boolean. The native attribute type Booleanish is not assignable to that prop, so the part declares disabled as Field.Control does. types.md has no row for a native attribute.

Return types that differ from Base UI: 0.

interactions

Matches the Base UI commit 5aacdbb of 2026-11-10.

Queued changes: 0.

Vase UI rows with no upstream row: 187.

FilesTotalPortedReplacedNot applicableWaits on
Sources1515000
Type tests00000
TestsTotalMatchedReplacedNot applicableWaits onEngine ChromiumEngine FirefoxEngine WebKit
Cases199194410000
Suite calls00000000

Exception rows: 5.

ThingKindReasonDetail
packages/react/src/utils/popups/interactions/useDismiss.test.tsx, case "useDismiss > default options > does not dismiss with the escape key that ends a composition spanning a reopen"replacedThe case asserts that Escape directly after compositionend keeps the popup open. Only WebKit sends compositionend before the keydown that ends a composition, so only WebKit needs that window. In the other engines Vase UI closes the popup (BUG-6158). The case "ignores Escape for 5 ms after compositionend in WebKit" tests the window in WebKit. Test: packages/vue/src/utils/popups/interactions/useDismiss.test.tsx
packages/react/src/utils/popups/interactions/useListNavigation.test.tsx, case "useListNavigation > focus management in nested lists"replacedBase UI runs the case only in jsdom. jsdom does not focus the first item at the open, and a browser does, so the keys of the case reach other items in a browser. In the block lists below the list in the component tree, the cases open a list below with its key, in a browser, and the first item of that list gets the focus. Test: packages/vue/src/utils/popups/interactions/useListNavigation.test.tsx
packages/react/src/utils/popups/interactions/useListNavigation.test.tsx, case "useListNavigation > keyboard navigation in nested menus lists"replacedBase UI runs the case only in jsdom. jsdom does not focus the first item at the open, and a browser does, so the keys of the case reach other items in a browser. The case moves in a grid of a list below, and closes that list for Escape of the block lists below the list in the component tree makes the same moves in a browser. Test: packages/vue/src/utils/popups/interactions/useListNavigation.test.tsx
packages/react/src/utils/popups/interactions/useListNavigation.test.tsx, case "useListNavigation > keyboard navigation in nested menus with different orientation"replacedBase UI runs the case only in jsdom. jsdom does not focus the first item at the open, and a browser does, so the keys of the case reach other items in a browser. The cases of VUE-46 in the block lists below the list in the component tree press the close key of a list below a horizontal list, in a browser. The list below closes, and the list above moves its highlight. Test: packages/vue/src/utils/popups/interactions/useListNavigation.test.tsx
packages/react/test/useTestInteractions.test.tsx, case "useTestInteractions > prop getters are memoized"not-applicablesetup runs one time, so the composable makes the getters one time and their identity cannot change. React makes new getters when a props object of the list changes. A new case covers the half that applies: a getter reads the current props of an entry that changes.

Additions to the Base UI API: 0.

Return types that differ from Base UI: 0.

internals

Matches the Base UI commit 5aacdbb of 2026-11-10.

Queued changes: 0.

Vase UI rows with no upstream row: 86.

FilesTotalPortedReplacedNot applicableWaits on
Sources8075050
Type tests21010
TestsTotalMatchedReplacedNot applicableWaits onEngine ChromiumEngine FirefoxEngine WebKit
Cases2752482250000
Suite calls22000000

Exception rows: 23.

ThingKindReasonDetail
packages/react/test/hiddenInputTypeTests.tsx, case "hidden input type > stays focusable through inputRef"not-applicableThe case gives the React ref prop inputRef. A part of Vase UI exposes its input as inputElement, and a part cannot know if a consumer reads an exposed member. With no name, no autoComplete, no required and no field, the input thus stays type="hidden", which cannot take the focus. A consumer that focuses the input gives the control one of them.
packages/react/src/internals/useRenderElement.test.tsx, case "useRenderElement > updates merged refs and event handlers when ref shape changes across rerenders"not-applicableA part gives its ref callbacks one time, in setup, so their shape cannot change. React makes a new merged ref when the ref argument changes. A new test covers the handler half: a listener of the part that changes between two renders.
packages/react/src/internals/useRenderElement.test.tsx, case "useRenderElement > prop: render > warns when render is passed a function with an uppercase name"not-applicableThe warning is for a React component that is given as the render function. In Vue the as prop takes a component, and #render is a slot.
packages/react/src/internals/useRenderElement.test.tsx, case "useRenderElement > prop: render > warns when render is passed a function with an uppercase acronym prefix"not-applicableThe warning is for a React component that is given as the render function. In Vue the as prop takes a component, and #render is a slot.
packages/react/src/internals/useRenderElement.test.tsx, case "useRenderElement > prop: render > does not warn when render is passed a lowercase callback"not-applicableThe warning is for a React component that is given as the render function. In Vue the as prop takes a component, and #render is a slot.
packages/react/src/internals/useRenderElement.test.tsx, case "useRenderElement > prop: render > does not warn when render is passed a screaming snake case callback"not-applicableThe warning is for a React component that is given as the render function. In Vue the as prop takes a component, and #render is a slot.
packages/react/src/internals/useRenderElement.test.tsx, case "useRenderElement > prop: render > does not warn when render is passed a callback with an inferred useCallback name"not-applicableThe warning is for a React component that is given as the render function. In Vue the as prop takes a component, and #render is a slot.
packages/react/src/internals/useRenderElement.test.tsx, case "useRenderElement > prop: render > does not warn when render is passed as a React element"not-applicableThe warning is for a React component that is given as the render function. In Vue the as prop takes a component, and #render is a slot.
packages/react/src/internals/useRenderElement.test.tsx, block "useRenderElement > prop: render > lazy-wrapped render element (Flight shape)"not-applicableThe cases test the lazy wrapper that the Flight client of React Server Components gives in place of a render element.
packages/react/src/internals/useRenderElement.test.tsx, case "useRenderElement > prop: render > throws error for invalid render element in development"not-applicableThe case tests React.isValidElement and React.cloneElement. No part clones a vnode.
packages/react/src/internals/useRenderElement.spec.tsxnot-applicableThe file tests that the result type follows enabled. The Vue composable has no enabled parameter: the template decides with v-if.
packages/react/src/internals/use-button/useButton.test.tsx, block "useButton > server-side rendering"replacedA server render runs in Node with no DOM. The cases are in the test file that the Node project runs, with the same titles. Test: packages/vue/src/internals/use-button/useButton.node.test.tsx
packages/react/src/internals/composite/list/CompositeList.tsxnot-applicableThe file is a React component that gives the list context to its children. A Vue part calls useCompositeList of list/useCompositeList.ts in setup, which holds the registry of this file, and renders its own element.
packages/react/src/internals/composite/list/CompositeList.test.tsx, case "<CompositeList /> > prop: elementsRef > syncs replacement refs without publishing an unchanged map"not-applicableThe case replaces the ref objects of a mounted list. A Vue part gives elementsRef and labelsRef one time, in setup. The new case does not publish an unchanged map when a label changes covers the half that applies.
packages/react/src/internals/composite/list/CompositeList.test.tsx, block "<CompositeList /> > Suspense integration"not-applicableReact hides a mounted tree and detaches its refs when a component in it suspends again. A mounted Vue component cannot suspend again.
packages/react/src/internals/composite/root/CompositeRoot.tsxnot-applicableThe file is a React component that renders the element of a part and gives it the composite context. A Vue part renders its own element and calls useCompositeRoot of root/useCompositeRoot.ts in setup, which holds the work of this file.
packages/react/src/internals/composite/item/CompositeItem.tsxnot-applicableThe file is a React component that renders the element of an item part and gives it the tab stop. A Vue part renders its own element and calls useCompositeItem of item/useCompositeItem.ts in setup, which holds the work of this file.
packages/react/src/internals/resolvePopupLabel.test.tsx, case "resolvePopupLabel > uses a render element's own label instead of the trigger"not-applicableThe case gives a React element with an aria-label as render. In Vue #render is a slot, which is a function, so the part does not see an attribute of the element of the slot. resolvePopupLabel reads the attributes of the part.
packages/react/src/internals/resolvePopupLabel.test.tsx, case "resolvePopupLabel > reads a server-created render element's label"not-applicableThe case gives the lazy wrapper of the React Flight client as render.
packages/react/src/internals/resolveRenderedAriaLabel.tsnot-applicableThe file reads the aria-label of a React element that is given as render. In Vue the as prop takes a tag or a component with no props of its own, and #render is a slot, which is a function. A control reads its aria-label prop.
packages/react/src/internals/resolveRenderedAriaLabel.test.tsxnot-applicableThe cases test resolveRenderedAriaLabel, which reads a React element that is given as render.
packages/react/src/internals/composite/index.tsnot-applicableNo Base UI component imports the file. It is the module of the package entry ./internals/composite, and Vase UI has no entry point for an internal module.
packages/react/src/internals/useItemRegistry.test.tsx, case "useItemRegistry > publishes every registration under StrictMode double effects"not-applicableThe case runs the effects of the items two times under StrictMode. Vue has no Strict Mode, and a registration runs one time in onMounted.

Additions to the Base UI API: 0.

Return types that differ from Base UI: 0.

Matches the Base UI commit 5aacdbb of 2026-11-10.

Queued changes: 0.

Vase UI rows with no upstream row: 207.

FilesTotalPortedReplacedNot applicableWaits on
Sources7676000
Type tests33000
TestsTotalMatchedReplacedNot applicableWaits onEngine ChromiumEngine FirefoxEngine WebKit
Cases5725583110000
Suite calls4040000000
APITotalMatchedExcepted
Entries46460
Prop rows1651614

Exception rows: 17.

ThingKindReasonDetail
packages/react/src/menu/filter-root/MenuFilterRoot.react17.test.tsxnot-applicableThe cases are for React 17, which has no useId. useVaseUiId gives an id in setup.
packages/react/src/menu/filter-root/MenuFilterRoot.test.tsx, case "<Menu.FilterProvider><Menu.Root/></Menu.FilterProvider> > filtering > uses the id from a custom trigger render element for popup labelling"not-applicableThe case gives a React element with an id as render. In Vue #render is a slot, which is a function, so the part does not see the id of the element of the slot. The id prop gives the same result.
packages/react/src/menu/filter-root/MenuFilterRoot.test.tsx, case "<Menu.FilterProvider><Menu.Root/></Menu.FilterProvider> > filtering > uses an explicit label from the popup render element"not-applicableThe case gives a React element with an aria-label as render. In Vue #render is a slot, which is a function, so the part does not see the aria-label of the element of the slot. The aria-label attribute of the part gives the same result.
packages/react/src/menu/filter-root/MenuFilterRoot.test.tsx, case "<Menu.FilterProvider><Menu.Root/></Menu.FilterProvider> > accessible names > keeps a list label supplied through a render element"not-applicableThe case gives a React element with an attribute of the list as render. In Vue #render is a slot, which is a function, so the part does not see an attribute of the element of the slot. The attribute of the part gives the same result.
packages/react/src/menu/filter-root/MenuFilterRoot.test.tsx, case "<Menu.FilterProvider><Menu.Root/></Menu.FilterProvider> > accessible names > omits aria-controls when the list renders with an explicitly empty id"not-applicableThe case gives a React element with an id as render. In Vue #render is a slot, which is a function, so the part does not see the id of the element of the slot. The id prop gives the same result.
packages/react/src/menu/filter-root/MenuFilterRoot.test.tsx, case "<Menu.FilterProvider><Menu.Root/></Menu.FilterProvider> > accessible names > points aria-controls at the id of a server-created render element"not-applicableThe case gives the lazy wrapper of the React Flight client as render.
packages/react/src/menu/filter-root/MenuFilterRoot.webkit.test.tsx, case "<Menu.FilterProvider><Menu.Root/></Menu.FilterProvider> (WebKit) > keeps selection state for an auto-focused input in Strict Mode"not-applicableThe case checks the selection state after the double effects of Strict Mode. Vue has no Strict Mode.
packages/react/src/menu/root/MenuRoot.test.tsx, case "<Menu.Root /> > warns that nested menus ignore the modal prop"replacedThe case gives modal to Menu.SubmenuRoot through a cast. That part has no such prop in Vase UI, and Vue warns about the attribute. The case 'warns that a menu in a menubar ignores modal={false}' covers the warning of Vase UI. Test: packages/vue/src/menu/root/MenuRoot.test.tsx
packages/react/src/menu/root/MenuRoot.test.tsx, case "<Menu.Root /> > does not emit the nested modal warning in production"replacedThe case runs only in jsdom, and it sets process.env.NODE_ENV to production. Vitest sets that value when it transforms a file for a browser, so only the Node project can change it. The case 'gives no warning for modal in a production build' of the Node file covers it. Test: packages/vue/src/menu/root/MenuRoot.node.test.tsx
packages/react/src/menu/root/MenuRoot.test.tsx, case "<Menu.Root /> > submenu parent store subscription > releases the subscriptions a submenu adds to its parent store when it unmounts"not-applicableA submenu of Vase UI adds no subscription to the store of its parent. A selector of its store reads the reactive state of the parent.
packages/react/src/menu/root/MenuRoot.test.tsx, case "<Menu.Root /> > submenu parent store subscription > releases them under StrictMode"not-applicableVue has no Strict Mode. A submenu of Vase UI adds no subscription to the store of its parent.
packages/react/src/menu/submenu-trigger/MenuSubmenuTrigger.test.tsx, case "<Menu.SubmenuTrigger /> > prop: disabled > warns without an owner stack when React cannot provide one"not-applicablecaptureOwnerStack is a React API. The warning of Vase UI has no owner stack.
packages/react/src/menu/submenu-trigger/MenuSubmenuTrigger.test.tsx, case "<Menu.SubmenuTrigger /> > prop: disabled > does not inspect rendered disabled elements in production"replacedThe case needs a production build. Vitest sets process.env.NODE_ENV when it transforms a file for a browser, so only the Node project can change it. A server render calls no onMounted hook, so the Node case asserts only that a server render in a production build gives no warning. Test: packages/vue/src/menu/submenu-trigger/MenuSubmenuTrigger.node.test.tsx
docs/src/app/(docs)/react/components/menu/types.md, entry "Positioner", prop "side"not-applicableThe row gives the default 'bottom'. The part has no Vue default: a prop that is absent takes 'inline-end' for a submenu and for a menubar with a vertical orientation, and 'bottom' for any other menu, as in Base UI. With a Vue default, the part cannot find out that the prop is absent.
docs/src/app/(docs)/react/components/menu/types.md, entry "Positioner", prop "align"not-applicableThe row gives the default 'center'. The part has no Vue default: a prop that is absent takes 'start' for a submenu, a menubar and a context menu, and 'center' for any other menu, as in Base UI. With a Vue default, the part cannot find out that the prop is absent.
docs/src/app/(docs)/react/components/menu/types.md, entry "Positioner", prop "sideOffset"not-applicableThe row gives the default 0. The part has no Vue default: a prop that is absent takes -5 for a context menu that has no side and an align other than 'center', and 0 for any other menu, as in Base UI. With a Vue default, the part cannot find out that the prop is absent.
docs/src/app/(docs)/react/components/menu/types.md, entry "Positioner", prop "alignOffset"not-applicableThe row gives the default 0. The part has no Vue default: a prop that is absent takes 2 for a context menu that has no side and an align other than 'center', and 0 for any other menu, as in Base UI. With a Vue default, the part cannot find out that the prop is absent.

Additions to the Base UI API: 11.

EntryKindNameReason
TriggerpropidThe part reads id to register the trigger in the store of the menu, so it is a declared prop. Base UI reads it from the native attributes of the trigger, and types.md has no row for a native attribute.
InputpropidThe part replaces an absent id with a generated id and renders it on the input, so it is a declared prop. Base UI reads it from the native attributes of the input, and types.md has no row for a native attribute.
InputpropdisabledThe part reads disabled for its state and for the attribute of the input, so it is a declared prop. Base UI reads it from the native attributes of the input, and types.md has no row for a native attribute.
ListpropidThe part replaces an absent id with a generated id and gives it to the store, which the trigger names in aria-controls. It is thus a declared prop. Base UI reads it from the native attributes of the list, and types.md has no row for a native attribute.
PopuppropidThe part replaces an absent id with a generated id and gives the id to the root, which the trigger names in aria-controls. Base UI declares id as a prop with the tag @ignore, so types.md has no row for it.
ItempropidThe part replaces an absent id with a generated id and renders it on the item. Base UI declares id as a prop with the tag @ignore, so types.md has no row for it.
LinkItempropidThe part replaces an absent id with a generated id and renders it on the link. Base UI declares id as a prop with the tag @ignore, so types.md has no row for it.
SubmenuTriggerpropidThe part replaces an absent id with a generated id and registers the trigger in the store of the submenu with it. Base UI declares id as a prop with the tag @ignore, so types.md has no row for it.
GroupLabelpropidThe part replaces an absent id with a generated id and gives it to the group for aria-labelledby. It is thus a declared prop. Base UI reads it from the native attributes of the label, and types.md has no row for a native attribute.
RadioItempropidThe part replaces an absent id with a generated id and renders it on the item. Base UI declares id as a prop with the tag @ignore, so types.md has no row for it.
CheckboxItempropidThe part replaces an absent id with a generated id and renders it on the item. Base UI declares id as a prop with the tag @ignore, so types.md has no row for it.

Return types that differ from Base UI: 2.

EntryVase UI returnsReason
createHandleMenuHandle<Payload>Menu.Handle is the class MenuHandle. The declaration of the function names the class, and Base UI documents the same class by its name in the namespace.
useFilterFilterBase UI documents the return type as MenuFilter. The function returns Filter, and MenuFilter is that type under another name.

Matches the Base UI commit 5aacdbb of 2026-11-10.

Queued changes: 0.

Vase UI rows with no upstream row: 18.

FilesTotalPortedReplacedNot applicableWaits on
Sources44000
Type tests00000
TestsTotalMatchedReplacedNot applicableWaits onEngine ChromiumEngine FirefoxEngine WebKit
Cases4444000000
Suite calls11000000
APITotalMatchedExcepted
Entries220
Prop rows770

Exception rows: 0.

Additions to the Base UI API: 1.

EntryKindNameReason
MenubarpropidThe part reads id to give it to the menus of the menubar as the id of their root, so it is a declared prop. Base UI reads it from the native attributes of the menubar, and types.md has no row for a native attribute.

Return types that differ from Base UI: 0.

merge-props

Matches the Base UI commit 5aacdbb of 2026-11-10.

Queued changes: 0.

Vase UI rows with no upstream row: 9.

FilesTotalPortedReplacedNot applicableWaits on
Sources22000
Type tests00000
TestsTotalMatchedReplacedNot applicableWaits onEngine ChromiumEngine FirefoxEngine WebKit
Cases3030000000
Suite calls00000000
APITotalMatchedExcepted
Entries440
Prop rows000

Exception rows: 0.

Additions to the Base UI API: 0.

Return types that differ from Base UI: 3.

EntryVase UI returnsReason
makeEventPreventableVaseUIEvent<T>Vue has no synthetic event. The event is the DOM event, and VaseUIEvent adds preventVaseUIHandler() to it.
mergePropsMergedProps<T>With a type argument, the type is NativeElements[T]: the attributes of the element T, as Vue declares them. With no type argument, it is NativeElements['div']: the attributes that each HTML element has. Base UI's type is then in effect any. Each listener gets the DOM event, so a template can bind the result. Each handler of a set gets a VaseUIEvent.
mergePropsNMergedProps<T>With a type argument, the type is NativeElements[T]: the attributes of the element T, as Vue declares them. With no type argument, it is NativeElements['div']: the attributes that each HTML element has. Base UI's type is then in effect any. Each listener gets the DOM event, so a template can bind the result. Each handler of a set gets a VaseUIEvent.

meter

Matches the Base UI commit 5aacdbb of 2026-11-10.

Queued changes: 0.

Vase UI rows with no upstream row: 10.

FilesTotalPortedReplacedNot applicableWaits on
Sources88000
Type tests00000
TestsTotalMatchedReplacedNot applicableWaits onEngine ChromiumEngine FirefoxEngine WebKit
Cases2525000000
Suite calls55000000
APITotalMatchedExcepted
Entries550
Prop rows23221

Exception rows: 1.

ThingKindReasonDetail
docs/src/app/(docs)/react/components/meter/types.md, entry "Root", prop "aria-valuetext"not-applicableThe row documents a native attribute that the React part does not read. In Vase UI the attribute goes to the element through the attributes, with its type from HTMLAttributes. A declared prop would take it out of the attributes.

Additions to the Base UI API: 1.

EntryKindNameReason
LabelpropidThe part reads id to give it to the root for aria-labelledby, so it is a declared prop. Base UI reads it from the native attributes of the label, and types.md has no row for a native attribute.

Return types that differ from Base UI: 0.

Matches the Base UI commit 5aacdbb of 2026-11-10.

Queued changes: 0.

Vase UI rows with no upstream row: 108.

FilesTotalPortedReplacedNot applicableWaits on
Sources3333000
Type tests22000
TestsTotalMatchedReplacedNot applicableWaits onEngine ChromiumEngine FirefoxEngine WebKit
Cases129122520000
Suite calls1313000000
APITotalMatchedExcepted
Entries23230
Prop rows67661

Exception rows: 6.

ThingKindReasonDetail
packages/react/src/navigation-menu/content/NavigationMenuContent.test.tsx, block "<NavigationMenu.Content /> > server-side rendering"replacedEach case of the block renders on a server with no hydration, so each case is in the Node file of the folder. Test: packages/vue/src/navigation-menu/content/NavigationMenuContent.node.test.tsx
packages/react/src/navigation-menu/trigger/NavigationMenuTrigger.test.tsx, case "<NavigationMenu.Trigger /> > handles focus and positioner height"replacedBase UI runs its browser tests only in Chromium, and the case asserts pixel sizes of the default font of Chromium. Firefox and WebKit have other default fonts. The Vase UI case compares the size variable of the positioner with the measured size of the content, so it runs in each engine. Test: packages/vue/src/navigation-menu/trigger/NavigationMenuTrigger.test.tsx
packages/react/src/navigation-menu/trigger/NavigationMenuTrigger.test.tsx, case "<NavigationMenu.Trigger /> > handles positioner width correctly"replacedBase UI runs its browser tests only in Chromium, and the case asserts pixel sizes of the default font of Chromium. Firefox and WebKit have other default fonts. The Vase UI case compares the size variable of the positioner with the measured size of the content, so it runs in each engine. Test: packages/vue/src/navigation-menu/trigger/NavigationMenuTrigger.test.tsx
packages/react/src/navigation-menu/root/NavigationMenuRoot.test.tsx, case "<NavigationMenu.Root /> > nested menus > inline nested viewport > does not animate popup sizing when kept nested default content first moves into the portal"replacedThe case gives the popup a shell height for the first read of offsetHeight and the full height for the next reads, after the click. In Vue, the popup measures its open size in the flush of the click, before the case can mock the size, and the kept nested content is in the portal at that measure. The Vase UI case measures the real layout: each fixed height of the popup is its open height. Test: packages/vue/src/navigation-menu/root/NavigationMenuRoot.test.tsx
packages/react/src/navigation-menu/root/NavigationMenuRootContext.test.tsnot-applicableThe cases assert the displayName of a React context. A Vue injection key has no such name.
docs/src/app/(docs)/react/components/navigation-menu/types.md, entry "Root", prop "render"not-applicableThe default tag is nav, or div when the root is nested. The part decides it in setup, so the prop as has no static default.

Additions to the Base UI API: 2.

EntryKindNameReason
PopuppropidThe part reads id to replace an absent id with a generated id, which the active trigger names in aria-controls. It is thus a declared prop. Base UI reads it from the native attributes of the popup, and types.md has no row for a native attribute.
ViewportpropidThe part reads id to replace an absent id with a generated id, which the owner element of the active trigger names in aria-owns. It is thus a declared prop. Base UI reads it from the native attributes of the viewport, and types.md has no row for a native attribute.

Return types that differ from Base UI: 0.

number-field

Matches the Base UI commit 5aacdbb of 2026-11-10.

Queued changes: 0.

Vase UI rows with no upstream row: 87.

FilesTotalPortedReplacedNot applicableWaits on
Sources2525000
Type tests22000
TestsTotalMatchedReplacedNot applicableWaits onEngine ChromiumEngine FirefoxEngine WebKit
Cases475473110000
Suite calls88000000
APITotalMatchedExcepted
Entries14140
Prop rows48471

Exception rows: 3.

ThingKindReasonDetail
packages/react/src/number-field/input/NumberFieldInput.test.tsx, case "<NumberField.Input /> > warns without an owner stack when React cannot provide one"not-applicableThe case tests the owner stack of React. Vue has no owner stack.
packages/react/src/number-field/utils/parse.test.ts, case "NumberField parse > parseNumber > keeps only the last of many dots"replacedThe case reads .0.0.0 … .5 as 0.5. Vase UI does not read dots that are not group separators (BUG-5424, https://github.com/mui/base-ui/issues/5424), so that text gives null. The case "BUG-5424: keeps only the last of many dots that are group separators" tests the same count of dots with groups of three digits, and it tests that the text of Base UI gives null. Test: packages/vue/src/number-field/utils/parse.test.ts
docs/src/app/(docs)/react/components/number-field/types.md, entry "Input", prop "aria-roledescription"not-applicableThe row documents a native attribute and its default. In Vase UI the attribute goes to the element through the attributes, with its type from InputHTMLAttributes, and it replaces the default 'Number field'. A declared prop would take it out of the attributes.

Additions to the Base UI API: 2.

EntryKindNameReason
IncrementpropdisabledThe part reads disabled for its state and for useButton, so it is a declared prop. Base UI reads it from the native attributes of the button, and types.md has no row for a native attribute.
DecrementpropdisabledThe part reads disabled for its state and for useButton, so it is a declared prop. Base UI reads it from the native attributes of the button, and types.md has no row for a native attribute.

Return types that differ from Base UI: 0.

otp-field

Matches the Base UI commit 5aacdbb of 2026-11-10.

Queued changes: 0.

Vase UI rows with no upstream row: 54.

FilesTotalPortedReplacedNot applicableWaits on
Sources99000
Type tests22000
TestsTotalMatchedReplacedNot applicableWaits onEngine ChromiumEngine FirefoxEngine WebKit
Cases163159310000
Suite calls33000000
APITotalMatchedExcepted
Entries660
Prop rows28280

Exception rows: 3.

ThingKindReasonDetail
packages/react/src/otp-field/root/OTPFieldRoot.react17.test.tsxnot-applicableThe file mocks SafeReact to test the id fallback of React 17. Vue has useId in each version that the package supports.
packages/react/src/otp-field/root/OTPFieldRoot.test.tsx, case "<OTPField.Root /> > value handling > prop: validationType > hidden validation input > renders the hidden validation input with an alphanumeric pattern during SSR"replacedA server render with no hydrate() runs in Node with no DOM. The case is in the test file that the Node project runs, with the same titles. Test: packages/vue/src/otp-field/root/OTPFieldRoot.node.test.tsx
packages/react/src/otp-field/root/OTPFieldRoot.test.tsx, block "<OTPField.Root /> > Form > server-side rendering"replacedA server render runs in Node with no DOM. The two cases are in the test file that the Node project runs, with the same titles. Test: packages/vue/src/otp-field/root/OTPFieldRoot.node.test.tsx

Additions to the Base UI API: 2.

EntryKindNameReason
RootpropariaLabelledbyThe part reads aria-labelledby to find out if a label names the group and the inputs, and $attrs is not reactive, so it is a declared prop. Base UI reads it from the native attributes of the element, and types.md has no row for a native attribute.
RootchangeEventReasonnoneA native reset changes the value. Base UI does not follow a reset.

Return types that differ from Base UI: 0.

popover

Matches the Base UI commit 5aacdbb of 2026-11-10.

Queued changes: 0.

Vase UI rows with no upstream row: 57.

FilesTotalPortedReplacedNot applicableWaits on
Sources2929000
Type tests22000
TestsTotalMatchedReplacedNot applicableWaits onEngine ChromiumEngine FirefoxEngine WebKit
Cases163160030000
Suite calls1515000000
APITotalMatchedExcepted
Entries22220
Prop rows65650

Exception rows: 3.

ThingKindReasonDetail
packages/react/src/popover/root/PopoverRoot.detached-triggers.test.tsx, case "<Popover.Root /> > hands off hover between detached triggers when the rendered component retains a stale ref"not-applicableThe case renders a component that keeps the first ref callback that it got. A part gives its ref callbacks one time, in setup, and the callback of a trigger only writes the element to a ref. A watcher on the element, the id and the store then registers the trigger on the store that it has at that time. A callback that a component keeps thus cannot register the trigger on the store that the trigger left.
packages/react/src/popover/root/PopoverRoot.detached-triggers.test.tsx, case "<Popover.Root /> > keeps registration on the attached store when a stale-ref component swaps its host node"not-applicableThe case renders a component that keeps the first ref callback that it got, and swaps its host node. A part gives its ref callbacks one time, in setup, and the callback of a trigger only writes the element to a ref. The watcher of the registration then moves the registration to the new element on the store that the trigger has at that time.
packages/react/src/popover/root/PopoverRoot.detached-triggers.test.tsx, case "<Popover.Root /> > does not detach the consumer ref when the handle attaches to a root"not-applicableThe case counts the calls of the ref callback of a consumer. Base UI merges that callback with the ref callbacks of the part. A new merged ref for a change of the store would give the consumer a call with null and a new call, and the case guards against it. A part gives its own ref callbacks one time, in setup, and Vue does not merge the ref of a consumer with them. A change of the store thus changes no ref.

Additions to the Base UI API: 4.

EntryKindNameReason
TriggerpropdisabledThe part reads disabled for its state and for useButton, so it is a declared prop. Base UI reads it from the native attributes of the trigger, and types.md has no row for a native attribute.
TitlepropidThe part reads id to register it with the root for aria-labelledby of the popup, so it is a declared prop. Base UI reads it from the native attributes of the title, and types.md has no row for a native attribute.
DescriptionpropidThe part reads id to register it with the root for aria-describedby of the popup, so it is a declared prop. Base UI reads it from the native attributes of the description, and types.md has no row for a native attribute.
ClosepropdisabledThe part reads disabled for its state and for useButton, so it is a declared prop. Base UI reads it from the native attributes of the button, and types.md has no row for a native attribute.

Return types that differ from Base UI: 1.

EntryVase UI returnsReason
createHandlePopoverHandle<Payload>Popover.Handle is the class PopoverHandle. The declaration of the function names the class, and Base UI documents the same class by its name in the namespace.

popups

Matches the Base UI commit 5aacdbb of 2026-11-10.

Queued changes: 0.

Vase UI rows with no upstream row: 125.

FilesTotalPortedReplacedNot applicableWaits on
Sources3232000
Type tests22000
TestsTotalMatchedReplacedNot applicableWaits onEngine ChromiumEngine FirefoxEngine WebKit
Cases265264100000
Suite calls00000000

Exception rows: 1.

ThingKindReasonDetail
packages/react/src/utils/popups/popupTriggerMap.test.ts, case "PopupTriggerMap > does not throw in production when the same element is registered under multiple ids"replacedThe case needs a production build. Vitest sets process.env.NODE_ENV when it transforms a file for a browser, so only the Node project can change it. Test: packages/vue/src/utils/popups/popupTriggerMap.node.test.ts

Additions to the Base UI API: 0.

Return types that differ from Base UI: 0.

portal

Matches the Base UI commit 5aacdbb of 2026-11-10.

Queued changes: 0.

Vase UI rows with no upstream row: 2.

FilesTotalPortedReplacedNot applicableWaits on
Sources22000
Type tests00000
TestsTotalMatchedReplacedNot applicableWaits onEngine ChromiumEngine FirefoxEngine WebKit
Cases1714120000
Suite calls00000000

Exception rows: 3.

ThingKindReasonDetail
packages/react/src/utils/popups/portal/FloatingPortal.test.tsx, case "$name container resolution > $name without canceling a view transition"not-applicableThe cases use React.ViewTransition to test that the retry of the container check does not cancel a view transition. Vue has no such retry.
packages/react/src/utils/popups/portal/FloatingPortal.test.tsx, case "$name container resolution > does not cancel a view transition that reveals a hidden pending portal"not-applicableThe case uses React.ViewTransition and React.Activity to test that the retry of the container check does not cancel a view transition. Vue has no such retry.
packages/react/src/utils/popups/portal/FloatingPortal.test.tsx, case "$name container resolution > mounts children once in a connected container when a later update replaces its ref"replacedThe Vue portal gets its container in the flush after the mount. When updates in that flush replace the container, the children mount in the first container. That container is out of the document when their onMounted hooks run. Vue then moves the children to the new container. The case "mounts the children once, and moves them when updates in the flush of the mount replace the container" tests this. Test: packages/vue/src/utils/popups/portal/FloatingPortalLite.test.tsx

Additions to the Base UI API: 0.

Return types that differ from Base UI: 0.

preview-card

Matches the Base UI commit 5aacdbb of 2026-11-10.

Queued changes: 0.

Vase UI rows with no upstream row: 30.

FilesTotalPortedReplacedNot applicableWaits on
Sources2424000
Type tests33000
TestsTotalMatchedReplacedNot applicableWaits onEngine ChromiumEngine FirefoxEngine WebKit
Cases5959000000
Suite calls1111000000
APITotalMatchedExcepted
Entries18180
Prop rows49490

Exception rows: 0.

Additions to the Base UI API: 1.

EntryKindNameReason
TriggerpropidThe part reads id to register the trigger in the store of the preview card, so it is a declared prop. Base UI reads it from the native attributes of the trigger, and types.md has no row for a native attribute.

Return types that differ from Base UI: 1.

EntryVase UI returnsReason
createHandlePreviewCardHandle<Payload>PreviewCard.Handle is the class PreviewCardHandle. The declaration of the function names the class, and Base UI documents the same class by its name in the namespace.

progress

Matches the Base UI commit 5aacdbb of 2026-11-10.

Queued changes: 0.

Vase UI rows with no upstream row: 10.

FilesTotalPortedReplacedNot applicableWaits on
Sources1414000
Type tests00000
TestsTotalMatchedReplacedNot applicableWaits onEngine ChromiumEngine FirefoxEngine WebKit
Cases2525000000
Suite calls55000000
APITotalMatchedExcepted
Entries10100
Prop rows23221

Exception rows: 1.

ThingKindReasonDetail
docs/src/app/(docs)/react/components/progress/types.md, entry "Root", prop "aria-valuetext"not-applicableThe row documents a native attribute that the React part does not read. In Vase UI the attribute goes to the element through the attributes, with its type from HTMLAttributes. A declared prop would take it out of the attributes.

Additions to the Base UI API: 1.

EntryKindNameReason
LabelpropidThe part reads id to give it to the root for aria-labelledby, so it is a declared prop. Base UI reads it from the native attributes of the label, and types.md has no row for a native attribute.

Return types that differ from Base UI: 0.

radio

Matches the Base UI commit 5aacdbb of 2026-11-10.

Queued changes: 0.

Vase UI rows with no upstream row: 15.

FilesTotalPortedReplacedNot applicableWaits on
Sources88000
Type tests11000
TestsTotalMatchedReplacedNot applicableWaits onEngine ChromiumEngine FirefoxEngine WebKit
Cases1918010000
Suite calls33000000
APITotalMatchedExcepted
Entries440
Prop rows13130

Exception rows: 1.

ThingKindReasonDetail
packages/react/src/radio/root/RadioRoot.test.tsx, case "<Radio.Root /> > prefers a render element's `aria-label` over an associated label"not-applicableThe case gives the aria-label as a prop of a React element in render. Base UI reads that prop with React.isValidElement. In Vue, an element with props of its own is the #render slot, and a part does not see an attribute that the slot adds. Base UI also does not see an attribute that a render function adds.

Additions to the Base UI API: 3.

EntryKindNameReason
RootpropidThe part reads id to name its hidden input and its element, and $attrs is not reactive, so it is a declared prop. Base UI reads it from the native attributes of the element, and types.md has no row for a native attribute.
RootpropariaLabelThe part reads aria-label to find out if a label names the radio, and $attrs is not reactive, so it is a declared prop. Base UI reads it from the native attributes of the element, and types.md has no row for a native attribute.
RootpropariaLabelledbyThe part reads aria-labelledby to find out if a label names the radio, and $attrs is not reactive, so it is a declared prop. Base UI reads it from the native attributes of the element, and types.md has no row for a native attribute.

Return types that differ from Base UI: 0.

radio-group

Matches the Base UI commit 5aacdbb of 2026-11-10.

Queued changes: 0.

Vase UI rows with no upstream row: 35.

FilesTotalPortedReplacedNot applicableWaits on
Sources44000
Type tests11000
TestsTotalMatchedReplacedNot applicableWaits onEngine ChromiumEngine FirefoxEngine WebKit
Cases8883050000
Suite calls11000000
APITotalMatchedExcepted
Entries624
Prop rows251213

Exception rows: 9.

ThingKindReasonDetail
packages/react/src/radio-group/RadioGroup.test.tsx, case "<RadioGroup /> > supports inputRef as a function"not-applicableThe case gives inputRef as a ref callback. Vue has no inputRef prop. The part exposes inputElement.
packages/react/src/radio-group/RadioGroup.test.tsx, case "<RadioGroup /> > does not detach a stable inputRef callback on unrelated re-renders"not-applicableThe case tests that a ref callback stays attached when the parent renders again. Vue has no inputRef prop. The part exposes inputElement.
packages/react/src/radio-group/RadioGroup.test.tsx, case "<RadioGroup /> > transfers the current input when the object inputRef changes"not-applicableThe case changes the inputRef prop from one ref object to another. Vue has no inputRef prop. The part exposes inputElement.
packages/react/src/radio-group/RadioGroup.test.tsx, case "<RadioGroup /> > detaches the previous callback inputRef when it changes (cleanup: %s)"not-applicableThe case changes the inputRef prop between ref callbacks, with and without a cleanup function. Vue has no inputRef prop. The part exposes inputElement.
packages/react/src/radio-group/RadioGroup.test.tsx, case "<RadioGroup /> > cleans up inputRef bindings when selecting, clearing, and unmounting"not-applicableThe case counts the cleanups of a ref callback. Vue has no inputRef prop. The cases "points inputRef to the checked radio input when present", "keeps inputRef pointing to the first radio when the value is cleared" and "detaches inputRef when its current radio unmounts" test the same changes of inputElement.
docs/src/app/(docs)/react/components/radio-group/types.md, entry "Root"not-applicableThe types.md of Radio Group repeats this entry of Radio. The family radio ports it.
docs/src/app/(docs)/react/components/radio-group/types.md, entry "Indicator"not-applicableThe types.md of Radio Group repeats this entry of Radio. The family radio ports it.
docs/src/app/(docs)/react/components/radio-group/types.md, entry "RadioRootDataAttributes"not-applicableThe types.md of Radio Group repeats this entry of Radio. The family radio ports it.
docs/src/app/(docs)/react/components/radio-group/types.md, entry "RadioIndicatorDataAttributes"not-applicableThe types.md of Radio Group repeats this entry of Radio. The family radio ports it.

Additions to the Base UI API: 1.

EntryKindNameReason
RadioGrouppropidThe part gives id to the field as the id of its control and follows a change of it, so it is a declared prop. Base UI reads it from the native attributes of the element, and types.md has no row for a native attribute.

Return types that differ from Base UI: 0.

scroll-area

Matches the Base UI commit 5aacdbb of 2026-11-10.

Queued changes: 0.

Vase UI rows with no upstream row: 27.

FilesTotalPortedReplacedNot applicableWaits on
Sources2222000
Type tests00000
TestsTotalMatchedReplacedNot applicableWaits onEngine ChromiumEngine FirefoxEngine WebKit
Cases9897010000
Suite calls66000000
APITotalMatchedExcepted
Entries14140
Prop rows21210

Exception rows: 1.

ThingKindReasonDetail
packages/react/src/scroll-area/scrollbar/ScrollAreaScrollbar.test.tsx, case "<ScrollArea.Scrollbar /> > data-hovering attribute > adds [data-hovering] when the synthetic pointer target differs from the native path"not-applicableThe case dispatches pointerover and tests the target of a React synthetic enter event. A Vue listener gets the native event, whose path starts at its target. An own case covers the native event.

Additions to the Base UI API: 0.

Return types that differ from Base UI: 0.

select

Matches the Base UI commit 5aacdbb of 2026-11-10.

Queued changes: 0.

Vase UI rows with no upstream row: 81.

FilesTotalPortedReplacedNot applicableWaits on
Sources4040000
Type tests22000
TestsTotalMatchedReplacedNot applicableWaits onEngine ChromiumEngine FirefoxEngine WebKit
Cases332327410002
Suite calls2323000000
APITotalMatchedExcepted
Entries32320
Prop rows1091081

Exception rows: 8.

ThingKindReasonDetail
packages/react/src/select/root/SelectRoot.test.tsx, case "<Select.Root /> > server-side rendering > does not link Select.Label before hydration"replacedThe case renders on a server only. Vase UI links the label in the server HTML (VUE-51). The block "VUE-51: a label of the select" asserts aria-labelledby in the server HTML, with the label before and after the trigger. Test: packages/vue/src/select/root/SelectRoot.node.test.tsx
packages/react/src/select/root/SelectRoot.test.tsx, case "<Select.Root /> > prop: highlightItemOnHover > highlights an item on mouse move by default"engineWebKit sends a mousemove with no movement when a list scrolls under a pointer that does not move. In WebKit, the list navigation thus ignores a mousemove with no movement, and the hover of user-event sends one. Engine: webkit
packages/react/src/select/root/SelectRoot.test.tsx, case "<Select.Root /> > does not dismiss when pressing portalled content inside the popup but outside the list"replacedThe case presses a plain element in a portal in the popup. Vue gives that event to no listener of the popup element, so that element is outside the popup. A press in a child popup that Teleport moved is inside (VUE-4). The case "VUE-4: a press in a child popup that Teleport moved does not close the parent popup" tests that press. Test: packages/vue/src/utils/popups/interactions/useDismiss.test.tsx
packages/react/src/select/group-label/SelectGroupLabel.test.tsx, case "<Select.GroupLabel /> > replaces and unregisters its label in Strict Mode"not-applicableThe case tests React Strict Mode. Vue has no Strict Mode.
packages/react/src/select/item/SelectItem.test.tsx, case "<Select.Item /> > should select the item and close popup when clicked"replacedThe case renders Select.Item in Select.Positioner with no Select.Popup. The popup root unmounts after the exit animations of the popup element, so with no popup element the positioner stays mounted and visible after the close. The case "selects the item with a click and hides the positioner after the popup closes" renders the popup. Test: packages/vue/src/select/item/SelectItem.test.tsx
packages/react/src/select/item/SelectItem.test.tsx, case "<Select.Item /> > should highlight a hovered item and commit it with a mouse click"engineWebKit sends a mousemove with no movement when a list scrolls under a pointer that does not move. In WebKit, the list navigation thus ignores a mousemove with no movement, and the case dispatches one. Engine: webkit
packages/react/src/select/store.test.tsx, case "select store synchronization > synchronizes an updated disabled prop after descendant ref callbacks"replacedVue writes the props of the root to the store before the items render, so a click in the ref callback of that render does not select the item. The case "gives a new disabled prop of the root to the items in the render that changes it" asserts this. Test: packages/vue/src/select/store.test.tsx
docs/src/app/(docs)/react/components/select/types.md, entry "Root", prop "multiple"not-applicableThe row gives the default false. The prop has no declared default, because withDefaults refuses a default for a prop of the generic type Multiple & boolean (TS2322). Vue gives an absent Boolean prop the value false, and the JSDoc has @default false for the API reference.

Additions to the Base UI API: 2.

EntryKindNameReason
TriggerpropidThe part reads id to give the trigger its own id, which the labels of the select and of the field name, and $attrs is not reactive, so it is a declared prop. Base UI reads it from the native attributes of the trigger, and types.md has no row for a native attribute.
GroupLabelpropidThe part gives id to the group for aria-labelledby and follows a change of it, so it is a declared prop. Base UI reads it from the native attributes of the group label, and types.md has no row for a native attribute.

Return types that differ from Base UI: 0.

separator

Matches the Base UI commit 5aacdbb of 2026-11-10.

Queued changes: 0.

Vase UI rows with no upstream row: 2.

FilesTotalPortedReplacedNot applicableWaits on
Sources33000
Type tests00000
TestsTotalMatchedReplacedNot applicableWaits onEngine ChromiumEngine FirefoxEngine WebKit
Cases22000000
Suite calls11000000
APITotalMatchedExcepted
Entries220
Prop rows440

Exception rows: 0.

Additions to the Base UI API: 0.

Return types that differ from Base UI: 0.

slider

Matches the Base UI commit 5aacdbb of 2026-11-10.

Queued changes: 0.

Vase UI rows with no upstream row: 34.

FilesTotalPortedReplacedNot applicableWaits on
Sources2726010
Type tests11000
TestsTotalMatchedReplacedNot applicableWaits onEngine ChromiumEngine FirefoxEngine WebKit
Cases237235200000
Suite calls77000000
APITotalMatchedExcepted
Entries13130
Prop rows49472

Exception rows: 5.

ThingKindReasonDetail
packages/react/src/slider/thumb/prehydrationScript.template.jsnot-applicableBase UI turns this file into prehydrationScript.min.ts with a minifier. No component imports the template. Vase UI has no minifier.
packages/react/src/slider/root/SliderRoot.test.tsx, case "<Slider.Root /> > server-side rendering > does not link Slider.Label before hydration"replacedA server render with no hydrate() runs in Node with no DOM. The case asserts that the server HTML has no aria-labelledby on the root and on the input of the thumb. Vase UI has both attributes on the server. The root assumes its label until it is mounted. The thumb defers its render. Its input then has the id of the label, with the label before or after the control. The case "VUE-29: links the label to the root and to the input of each thumb, with the label $name" asserts the server HTML. Test: packages/vue/src/slider/root/SliderRoot.node.test.tsx
packages/react/src/slider/root/SliderRoot.test.tsx, case "<Slider.Root /> > prop: disabled > explicitly blurs the focused thumb when disabled"replacedBase UI runs the case only in jsdom, and it asserts a call of blur() with a spy. Firefox moves the focus off a disabled input itself, so the root has nothing to blur there. The case "does not keep the focus on a thumb that becomes disabled" asserts the result in each engine: the thumb does not keep the focus. Test: packages/vue/src/slider/root/SliderRoot.test.tsx
docs/src/app/(docs)/react/components/slider/types.md, entry "Thumb", prop "aria-valuetext"not-applicableThe part declares this prop as ariaValuetext, because Vue gives the attribute aria-valuetext to that prop. The prop has a row in surfaceAdditions.
docs/src/app/(docs)/react/components/slider/types.md, entry "Thumb", prop "tabIndex"not-applicableThe part declares this prop as tabindex, the name of the attribute in the types of Vue. The prop has a row in surfaceAdditions.

Additions to the Base UI API: 7.

EntryKindNameReason
RootpropidThe part reads id to make the id of Slider.Label, and $attrs is not reactive, so it is a declared prop. Base UI reads it from the native attributes of the root, and types.md has no row for a native attribute.
RootpropariaLabelledbyThe part reads aria-labelledby to name itself and the thumbs, and $attrs is not reactive, so it is a declared prop. Base UI reads it from the native attributes of the root, and types.md has no row for a native attribute.
ThumbpropariaLabelThe part gives aria-label to its input and not to its element, and $attrs is not reactive, so it is a declared prop. Base UI reads it from the native attributes of the thumb, and types.md has no row for a native attribute.
ThumbpropariaLabelledbyThe part gives aria-labelledby to its input and not to its element, and $attrs is not reactive, so it is a declared prop. Base UI reads it from the native attributes of the thumb, and types.md has no row for a native attribute.
ThumbpropariaDescribedbyThe part gives aria-describedby to its input and not to its element, and $attrs is not reactive, so it is a declared prop. Base UI reads it from the native attributes of the thumb, and types.md has no row for a native attribute.
ThumbpropariaValuetextThe prop is aria-valuetext of Base UI. Vue gives the attribute aria-valuetext to the prop ariaValuetext.
ThumbproptabindexThe prop is tabIndex of Base UI. A key in the types of Vue has the name of the attribute, tabindex.

Return types that differ from Base UI: 0.

switch

Matches the Base UI commit 5aacdbb of 2026-11-10.

Queued changes: 0.

Vase UI rows with no upstream row: 26.

FilesTotalPortedReplacedNot applicableWaits on
Sources88000
Type tests00000
TestsTotalMatchedReplacedNot applicableWaits onEngine ChromiumEngine FirefoxEngine WebKit
Cases6967110000
Suite calls33000000
APITotalMatchedExcepted
Entries440
Prop rows19190

Exception rows: 2.

ThingKindReasonDetail
packages/react/src/switch/root/SwitchRoot.test.tsx, case "<Switch.Root /> > extra props > prefers a render element's `aria-label` over an associated label"not-applicableThe case gives the aria-label as a prop of a React element in render. Base UI reads that prop with React.isValidElement. In Vue, an element with props of its own is the #render slot, and a part does not see an attribute that the slot adds. Base UI also does not see an attribute that a render function adds.
packages/react/src/switch/root/SwitchRoot.test.tsx, case "<Switch.Root /> > Form > preserves Field validation props through canceled changes, submit, and reset"replacedThe last lines of the case say that a native reset does not change the switch. Vase UI resets an uncontrolled switch to defaultChecked (BUG-6206). The case "preserves Field validation props through canceled changes, submit, and a native reset" has the other assertions of the upstream case and the reset of Vase UI. The block "BUG-6206: a native reset" tests the reset of a switch in a form. Test: packages/vue/src/switch/root/SwitchRoot.test.tsx

Additions to the Base UI API: 2.

EntryKindNameReason
RootpropariaLabelThe part reads aria-label to find out if a label names the switch, and $attrs is not reactive, so it is a declared prop. Base UI reads it from the native attributes of the element, and types.md has no row for a native attribute.
RootpropariaLabelledbyThe part reads aria-labelledby to find out if a label names the switch, and $attrs is not reactive, so it is a declared prop. Base UI reads it from the native attributes of the element, and types.md has no row for a native attribute.

Return types that differ from Base UI: 0.

tabs

Matches the Base UI commit 5aacdbb of 2026-11-10.

Queued changes: 0.

Vase UI rows with no upstream row: 32.

FilesTotalPortedReplacedNot applicableWaits on
Sources1817010
Type tests00000
TestsTotalMatchedReplacedNot applicableWaits onEngine ChromiumEngine FirefoxEngine WebKit
Cases142138310000
Suite calls55000000
APITotalMatchedExcepted
Entries11110
Prop rows27261

Exception rows: 6.

ThingKindReasonDetail
packages/react/src/tabs/panel/TabsPanel.test.tsx, case "<Tabs.Panel /> > Suspense integration > renders a panel that suspends when opened with the boundary outside the root"not-applicableReact hides the mounted tree and shows the fallback when a panel suspends after the mount. A mounted Vue component cannot suspend again.
docs/src/app/(docs)/react/components/tabs/types.md, entry "Root", prop "defaultValue"not-applicableThe part must tell an absent defaultValue from defaultValue={0}. Only the absent prop makes the root emit the initial change and fall back from a disabled tab. A Vue prop with a default cannot tell the two apart, so the prop has no default. The part uses 0 for an absent prop, which is the default that Base UI documents.
packages/react/src/tabs/indicator/prehydrationScript.template.jsnot-applicableBase UI turns this file into prehydrationScript.min.ts with a minifier. No component imports the template. Vase UI has no minifier and copies the minified text.
packages/react/src/tabs/indicator/TabsIndicator.test.tsx, case "<Tabs.Indicator /> > pre-hydration rendering > renders the inline pre-hydration script during server-side rendering"replacedA server render with no hydrate() runs in Node with no DOM. The case is in the test file that the Node project runs, with the same title. Test: packages/vue/src/tabs/indicator/TabsIndicator.node.test.tsx
packages/react/src/tabs/indicator/TabsIndicator.test.tsx, case "<Tabs.Indicator /> > pre-hydration rendering > inlines the script contents during server-side rendering"replacedA server render with no hydrate() runs in Node with no DOM. The case is in the test file that the Node project runs, with the same title. Test: packages/vue/src/tabs/indicator/TabsIndicator.node.test.tsx
packages/react/src/tabs/indicator/TabsIndicator.test.tsx, case "<Tabs.Indicator /> > pre-hydration rendering > applies the CSP nonce to the pre-hydration script"replacedA server render with no hydrate() runs in Node with no DOM. The case is in the test file that the Node project runs, with the same title. Test: packages/vue/src/tabs/indicator/TabsIndicator.node.test.tsx

Additions to the Base UI API: 2.

EntryKindNameReason
TabpropidThe part reads id to give it to the root for the aria-labelledby of the panel, so it is a declared prop. Base UI reads it from the native attributes of the tab, and types.md has no row for a native attribute.
PanelpropidThe part reads id to give it to the root for the aria-controls of the tab, so it is a declared prop. types.md has no row for a native attribute. Base UI gives the root a generated id, and an id of the consumer replaces only the id of the element.

Return types that differ from Base UI: 0.

toast

Matches the Base UI commit 5aacdbb of 2026-11-10.

Queued changes: 0.

Vase UI rows with no upstream row: 44.

FilesTotalPortedReplacedNot applicableWaits on
Sources3636000
Type tests22000
TestsTotalMatchedReplacedNot applicableWaits onEngine ChromiumEngine FirefoxEngine WebKit
Cases224218150000
Suite calls1010000000
APITotalMatchedExcepted
Entries25250
Prop rows524210

Exception rows: 16.

ThingKindReasonDetail
packages/react/src/toast/action/ToastAction.test.tsx, case "<Toast.Action /> > renders content passed through the render prop"not-applicableThe case gives its content in the React element of render, and the part reads the children of that element. A Vue part cannot read what its #render slot renders. It renders only while it has a default slot or the content of its toast.
packages/react/src/toast/provider/ToastProvider.test.tsx, case "<Toast.Provider /> > does not sync provider props from an abandoned render"not-applicableThe case suspends a React transition, and React then abandons a render. Vue has no render that it abandons.
packages/react/src/toast/utils/isRenderableNode.test.ts, case "hasRenderableChildren > requires an element whose children are renderable"replacedThe case builds React elements. A Vue part cannot read the children of a vnode, so Vase UI has no hasRenderableChildren. The cases of the label parts test the rule that replaces it: a part renders only while it has a default slot or a label with content. Test: packages/vue/src/toast/utils/useToastLabelPart.test.tsx
packages/react/src/toast/utils/useToastLabelPart.test.tsx, case "useToastLabelPart > <$name /> > prop: render > renders content passed through the render prop"not-applicableThe case gives its content in the React element of render, and the part reads the children of that element. A Vue part cannot read what its #render slot renders. It renders only while it has a default slot or the content of its toast.
packages/react/src/toast/utils/useToastLabelPart.test.tsx, case "useToastLabelPart > <$name /> > prop: render > renders content passed through a render function"not-applicableThe case gives its content in the React element of render, and the part reads the children of that element. A Vue part cannot read what its #render slot renders. It renders only while it has a default slot or the content of its toast.
packages/react/src/toast/utils/useToastLabelPart.test.tsx, case "useToastLabelPart > <$name /> > prop: render > `wires ${attribute} to a part rendered through the render prop`"not-applicableThe case gives its content in the React element of render, and the part reads the children of that element. A Vue part cannot read what its #render slot renders. It renders only while it has a default slot or the content of its toast.
docs/src/app/(docs)/react/components/toast/types.md, entry "Positioner", prop "disableAnchorTracking"not-applicableThe row gives the default false. The part has no Vue default: a prop that is absent takes disableAnchorTracking of positionerProps of the toast, and false when the toast has none, as in Base UI. With a Vue default, the part cannot find out that the prop is absent.
docs/src/app/(docs)/react/components/toast/types.md, entry "Positioner", prop "align"not-applicableThe row gives the default 'center'. The part has no Vue default: a prop that is absent takes align of positionerProps of the toast, and 'center' when the toast has none, as in Base UI. With a Vue default, the part cannot find out that the prop is absent.
docs/src/app/(docs)/react/components/toast/types.md, entry "Positioner", prop "alignOffset"not-applicableThe row gives the default 0. The part has no Vue default: a prop that is absent takes alignOffset of positionerProps of the toast, and 0 when the toast has none, as in Base UI. With a Vue default, the part cannot find out that the prop is absent.
docs/src/app/(docs)/react/components/toast/types.md, entry "Positioner", prop "side"not-applicableThe row gives the default 'top'. The part has no Vue default: a prop that is absent takes side of positionerProps of the toast, and 'top' when the toast has none, as in Base UI. With a Vue default, the part cannot find out that the prop is absent.
docs/src/app/(docs)/react/components/toast/types.md, entry "Positioner", prop "sideOffset"not-applicableThe row gives the default 0. The part has no Vue default: a prop that is absent takes sideOffset of positionerProps of the toast, and 0 when the toast has none, as in Base UI. With a Vue default, the part cannot find out that the prop is absent.
docs/src/app/(docs)/react/components/toast/types.md, entry "Positioner", prop "arrowPadding"not-applicableThe row gives the default 5. The part has no Vue default: a prop that is absent takes arrowPadding of positionerProps of the toast, and 5 when the toast has none, as in Base UI. With a Vue default, the part cannot find out that the prop is absent.
docs/src/app/(docs)/react/components/toast/types.md, entry "Positioner", prop "collisionBoundary"not-applicableThe row gives the default 'clipping-ancestors'. The part has no Vue default: a prop that is absent takes collisionBoundary of positionerProps of the toast, and 'clipping-ancestors' when the toast has none, as in Base UI. With a Vue default, the part cannot find out that the prop is absent.
docs/src/app/(docs)/react/components/toast/types.md, entry "Positioner", prop "collisionPadding"not-applicableThe row gives the default 5. The part has no Vue default: a prop that is absent takes collisionPadding of positionerProps of the toast, and 5 when the toast has none, as in Base UI. With a Vue default, the part cannot find out that the prop is absent.
docs/src/app/(docs)/react/components/toast/types.md, entry "Positioner", prop "sticky"not-applicableThe row gives the default false. The part has no Vue default: a prop that is absent takes sticky of positionerProps of the toast, and false when the toast has none, as in Base UI. With a Vue default, the part cannot find out that the prop is absent.
docs/src/app/(docs)/react/components/toast/types.md, entry "Positioner", prop "positionMethod"not-applicableThe row gives the default 'absolute'. The part has no Vue default: a prop that is absent takes positionMethod of positionerProps of the toast, and 'absolute' when the toast has none, as in Base UI. With a Vue default, the part cannot find out that the prop is absent.

Additions to the Base UI API: 4.

EntryKindNameReason
TitlepropidThe part gives id to the root for aria-labelledby and follows a change of it, so it is a declared prop. Base UI reads it from the native attributes of the title, and types.md has no row for a native attribute.
DescriptionpropidThe part gives id to the root for aria-describedby and follows a change of it, so it is a declared prop. Base UI reads it from the native attributes of the description, and types.md has no row for a native attribute.
ClosepropdisabledThe part reads disabled for useButton, so it is a declared prop. Base UI reads it from the native attributes of the button, and types.md has no row for a native attribute.
ActionpropdisabledThe part reads disabled for useButton, so it is a declared prop. Base UI reads it from the native attributes of the button, and types.md has no row for a native attribute.

Return types that differ from Base UI: 2.

EntryVase UI returnsReason
createToastManagerToastManager<Data>The source of Base UI returns the same type, ToastManager<Data>. Its types.md prints the type argument as {}.
useToastManagerUseToastManagerReturnValue<Data>setup runs one time, so a plain array does not follow a change of the toasts. toasts of the result is thus a ComputedRef of the array. The source of Base UI returns UseToastManagerReturnValue<Data>, and its types.md prints the type argument as {}.

toggle

Matches the Base UI commit 5aacdbb of 2026-11-10.

Queued changes: 0.

Vase UI rows with no upstream row: 8.

FilesTotalPortedReplacedNot applicableWaits on
Sources33000
Type tests00000
TestsTotalMatchedReplacedNot applicableWaits onEngine ChromiumEngine FirefoxEngine WebKit
Cases77000000
Suite calls11000000
APITotalMatchedExcepted
Entries220
Prop rows990

Exception rows: 0.

Additions to the Base UI API: 0.

Return types that differ from Base UI: 0.

toggle-group

Matches the Base UI commit 5aacdbb of 2026-11-10.

Queued changes: 0.

Vase UI rows with no upstream row: 7.

FilesTotalPortedReplacedNot applicableWaits on
Sources44000
Type tests11000
TestsTotalMatchedReplacedNot applicableWaits onEngine ChromiumEngine FirefoxEngine WebKit
Cases2323000000
Suite calls11000000
APITotalMatchedExcepted
Entries220
Prop rows10100

Exception rows: 0.

Additions to the Base UI API: 0.

Return types that differ from Base UI: 0.

toolbar

Matches the Base UI commit 5aacdbb of 2026-11-10.

Queued changes: 0.

Vase UI rows with no upstream row: 22.

FilesTotalPortedReplacedNot applicableWaits on
Sources1616000
Type tests11000
TestsTotalMatchedReplacedNot applicableWaits onEngine ChromiumEngine FirefoxEngine WebKit
Cases5757000000
Suite calls66000000
APITotalMatchedExcepted
Entries12120
Prop rows29290

Exception rows: 0.

Additions to the Base UI API: 0.

Return types that differ from Base UI: 0.

tooltip

Matches the Base UI commit 5aacdbb of 2026-11-10.

Queued changes: 0.

Vase UI rows with no upstream row: 36.

FilesTotalPortedReplacedNot applicableWaits on
Sources2424000
Type tests22000
TestsTotalMatchedReplacedNot applicableWaits onEngine ChromiumEngine FirefoxEngine WebKit
Cases121120100000
Suite calls1010000000
APITotalMatchedExcepted
Entries17170
Prop rows55532

Exception rows: 3.

ThingKindReasonDetail
packages/react/src/tooltip/root/TooltipRoot.test.tsx, case "<Tooltip.Root /> > hover changes > commits a hover open while the hover event is dispatched"replacedVue has no flushSync, so the popup renders in the update after the hover event, and a listener of the same event does not find it. The case shows the popup after the awaited hover event asserts the popup after the awaited event. Test: packages/vue/src/tooltip/root/TooltipRoot.test.tsx
docs/src/app/(docs)/react/components/tooltip/types.md, entry "Trigger", prop "delay"not-applicableThe row gives the default 600. The prop has no Vue default, because Base UI tells an absent prop from a number: an absent prop takes the delay of Tooltip.Provider. With no provider, the part uses 600 for an absent prop, which is the default that Base UI documents.
docs/src/app/(docs)/react/components/tooltip/types.md, entry "Trigger", prop "closeDelay"not-applicableThe row gives the default 0. The prop has no Vue default, because Base UI tells an absent prop from a number: an absent prop takes the close delay of Tooltip.Provider. With no provider, the part uses 0 for an absent prop, which is the default that Base UI documents.

Additions to the Base UI API: 1.

EntryKindNameReason
TriggerpropidThe part reads id to register the trigger in the store of the tooltip, so it is a declared prop. Base UI reads it from the native attributes of the trigger, and types.md has no row for a native attribute.

Return types that differ from Base UI: 1.

EntryVase UI returnsReason
createHandleTooltipHandle<Payload>Tooltip.Handle is the class TooltipHandle. The declaration of the function names the class, and Base UI documents the same class by its name in the namespace.

tree

Matches the Base UI commit 5aacdbb of 2026-11-10.

Queued changes: 0.

Vase UI rows with no upstream row: 0.

FilesTotalPortedReplacedNot applicableWaits on
Sources33000
Type tests00000
TestsTotalMatchedReplacedNot applicableWaits onEngine ChromiumEngine FirefoxEngine WebKit
Cases66000000
Suite calls00000000

Exception rows: 0.

Additions to the Base UI API: 0.

Return types that differ from Base UI: 0.

unstable-use-media-query

Matches the Base UI commit 5aacdbb of 2026-11-10.

Queued changes: 0.

Vase UI rows with no upstream row: 4.

FilesTotalPortedReplacedNot applicableWaits on
Sources11000
Type tests00000
TestsTotalMatchedReplacedNot applicableWaits onEngine ChromiumEngine FirefoxEngine WebKit
Cases42200000
Suite calls00000000

Exception rows: 2.

ThingKindReasonDetail
packages/react/src/unstable-use-media-query/index.test.tsx, case "useMediaQuery > uses ssrMatchMedia for the server snapshot"replacedA server render runs in Node with no DOM. The case is in the test file that the Node project runs, with the same title. Test: packages/vue/src/unstable-use-media-query/index.node.test.tsx
packages/react/src/unstable-use-media-query/index.test.tsx, case "useMediaQuery > uses the client matchMedia result as the server snapshot when noSsr is set"replacedA server render runs in Node with no DOM. The case is in the test file that the Node project runs, with the same title. Test: packages/vue/src/unstable-use-media-query/index.node.test.tsx

Additions to the Base UI API: 0.

Return types that differ from Base UI: 0.

use-render

Matches the Base UI commit 5aacdbb of 2026-11-10.

Queued changes: 0.

Vase UI rows with no upstream row: 4.

FilesTotalPortedReplacedNot applicableWaits on
Sources22000
Type tests11000
TestsTotalMatchedReplacedNot applicableWaits onEngine ChromiumEngine FirefoxEngine WebKit
Cases1414000000
Suite calls00000000
APITotalMatchedExcepted
Entries220
Prop rows000

Exception rows: 0.

Additions to the Base UI API: 0.

Return types that differ from Base UI: 1.

EntryVase UI returnsReason
useRenderuseRender.ReturnValue<RenderedElementType>A composable cannot return the rendered element. It returns element, elementProps and tag. The template of the component renders the element.

utils

Matches the Base UI commit 5aacdbb of 2026-11-10.

Queued changes: 0.

Vase UI rows with no upstream row: 36.

FilesTotalPortedReplacedNot applicableWaits on
Sources3028020
Type tests00000
TestsTotalMatchedReplacedNot applicableWaits onEngine ChromiumEngine FirefoxEngine WebKit
Cases4946120000
Suite calls11000000

Exception rows: 5.

ThingKindReasonDetail
packages/react/src/utils/getPseudoElementBounds.test.ts, case "getPseudoElementBounds > does not read pseudo-element styles in jsdom"not-applicableThe case tests the branch for jsdom, which has no getComputedStyle for a pseudo-element. Vase UI runs no test in jsdom, so the function has no such branch.
packages/react/src/utils/resolveRef.tsnot-applicableThe file reads the current of a React ref object. Vue toValue reads a ref, a getter or a value.
packages/react/src/utils/resolveStyle.tsnot-applicableThe file resolves the React style prop, which is an object or a function of the state. In Vase UI the style attribute and the stateStyle prop do this, and useRenderElement merges them. No Vase UI code needs the function.
packages/react/src/utils/useFormatLocale.test.tsx, case "useFormatLocale > returns the runtime locale on the first client-only render"not-applicableReact tells a hydration from a client-only mount with the server snapshot of useSyncExternalStore. Vue has no public API that tells them apart in setup, so the first render of a client-only mount also gets en-US. The case "returns en-US for the first render of a client-only mount, then the runtime locale" states what Vase UI does.
packages/react/src/utils/useIsHydrating.test.tsx, case "useIsHydrating > returns true before hydration for server-rendered markup"replacedA server render runs in Node with no DOM. The case is in the test file that the Node project runs, with the same title. Test: packages/vue/src/utils/useIsHydrating.node.test.tsx

Additions to the Base UI API: 0.

Return types that differ from Base UI: 0.

viewport

Matches the Base UI commit 5aacdbb of 2026-11-10.

Queued changes: 0.

Vase UI rows with no upstream row: 0.

FilesTotalPortedReplacedNot applicableWaits on
Sources55000
Type tests00000
TestsTotalMatchedReplacedNot applicableWaits onEngine ChromiumEngine FirefoxEngine WebKit
Cases1313000000
Suite calls00000000

Exception rows: 0.

Additions to the Base UI API: 0.

Return types that differ from Base UI: 0.

Base UI changes ​

Each change has a state for each family that it touches:

  • mirrored: the matched commit of the family is this commit or a later one.
  • queued: the matched commit of the family is older than this commit.
  • not applicable: the change does not apply to Vue. The table shows the reason.

A change that touches no family has one of two other states:

  • not started: the change is in a part of Base UI that Vase UI has not ported yet.
  • out of scope: Vase UI does not port the changed files. The table shows the reason when a rule names the files.
DateChangeCommitState
2026-11-10[docs][popover] Add close button to demos (#6095)5aacdbb
  • popover: mirrored.

Edge cases ​

Where Vue or the browser lets us handle an edge case better than the original, we do, and we list each one with its test.

IDBehaviorEvidenceDue withTests
BUG-1425When validationMode is onBlur, a required Radio Group with no value is invalid after the focus leaves it. The group or its field needs a name. In that mode, a required Select with no value is invalid after the focus leaves its trigger, and after an outside press closes its popup. A required Combobox with a selection mode and no value, whose trigger is the control, is invalid after the focus leaves its trigger, and after an outside press or a focus that leaves closes its popup. A Combobox whose input is outside the popup keeps the rule of a text field. Base UI shows no error until the form is submitted.packages/react/src/radio-group/RadioGroup.tsx
BUG-4678A Dialog, an Alert Dialog or a Drawer with modal set to true sets inert on the nodes outside the popup. Tab cannot reach those nodes, and a press cannot reach an element that is drawn above the backdrop. Live regions, scripts, nested portal nodes and focus guards do not get inert, as in Base UI. modal="trap-focus" and all other popups keep the aria-hidden marks of Base UI.packages/react/src/utils/popups/focus/markOthers.ts
BUG-4854A long press with a stylus opens the Context Menu.packages/react/src/context-menu/trigger/ContextMenuTrigger.tsx
BUG-5237In WebKit on an Apple system, the focus guard is a button with a name, so axe finds no violation.packages/react/src/utils/popups/focus/FocusGuard.tsx
BUG-5410A press in a same-origin iframe closes a popup that is not modal.packages/react/src/utils/popups/interactions/useDismiss.ts
BUG-5424A Number Field submits the number that it shows. Text with two dots or more is a number only when each dot before the last one can be a group separator, as in 1.234.567.89. A run of dots counts as one dot, as in Base UI: 1..5 in en-US and 1,,5 in de-DE are 1.5. Other text, such as 1.2.3, does not change the value. The rule also applies to the decimal separator of the locale: 1,2,3 in de-DE does not change the value. Base UI reads 1.2.3 as 12.3, so the field shows 1.2.3 and submits 12.3.packages/react/src/number-field/utils/parse.ts
BUG-5519During an exit animation, no focusable content is under aria-hidden. Combobox.Popup stops its focus manager when the popup closes, so its focus guards, which have aria-hidden, go at the close, and the focus returns at the close. Base UI stops the focus manager when the popup unmounts.packages/react/src/combobox/popup/ComboboxPopup.tsx
BUG-5574A pick with the mouse during an IME composition leaves no stale text in the input.packages/react/src/combobox/item/ComboboxItem.tsx
BUG-5577A popup that opens in a container that the marks of an earlier popup cover lifts aria-hidden, inert and data-vase-ui-inert from its own elements and their ancestors while it is open. The other children of those ancestors keep the marks, and the release of the later popup puts the marks back.packages/react/src/utils/popups/focus/markOthers.ts
BUG-5776Typeahead on a closed trigger does not select a mounted item that is disabled. The trigger reads the disabled state from the element of the item, so a label that comes from items while the list is not mounted still matches.packages/react/src/combobox/trigger/ComboboxTrigger.tsx
BUG-6037When a popup closes, focus goes to the first of these that can take it. The order is finalFocus, the trigger, the element that had focus before the popup opened, the parent popup (its first tabbable element, or the popup itself when it has none), and the newest element that had focus before an earlier open. When no click on the trigger opened the popup, the element that had focus before the popup opened comes before the trigger. An element that is not in the document, or that has the hidden attribute or an ancestor with it, cannot take focus. After a press on the backdrop in a browser without preventScroll, an explicit finalFocus still gets focus.packages/react/src/utils/popups/focus/FloatingFocusManager.tsx
BUG-6119The scroll lock probes the scrollbar gutter one time for each document. A later lock makes no layout probe, so it cannot stop a transition that runs.packages/utils/src/useScrollLock.ts
BUG-6158Escape closes the popup when the key comes directly after compositionend.packages/react/src/utils/popups/interactions/useDismiss.ts
BUG-6174The timers of a toast start again when focus goes into an iframe on the page.packages/react/src/toast/viewport/ToastViewport.tsx
BUG-6206A native form reset puts each uncontrolled control back to its default value and removes data-filled.packages/react/src/checkbox/root/CheckboxRoot.tsx
VUE-1A controlled Boolean prop that the consumer does not give stays undefined, and the part is uncontrolled. The same is true for an undefined binding, for kebab case and camel case, and for a Boolean prop with a generic type. :open="false", v-model:open and a bare attribute make the part controlled.packages/utils/src/useControlled.ts
VUE-2The server HTML has the label ids, the aria-* attributes and the roving tabindex. The DOM after hydration is equal to the DOM of a render with no server HTML.packages/react/src/radio-group/RadioGroup.tsx
VUE-3With Vue 3.5.41 or later on the server, the server HTML of a closed panel with hiddenUntilFound has hidden="until-found". In Vue 3.6, the server writes it from 3.6.0-rc.3. A server with an earlier Vue writes a bare hidden, and the part writes hidden="until-found" to the element at mount.packages/react/src/collapsible/panel/CollapsiblePanel.tsx
VUE-4A press in a child popup that Teleport moved does not close the parent popup. This includes a press on a part in its portal, such as Dialog.Backdrop. Escape closes the top popup first.packages/react/src/utils/popups/interactions/useDismiss.ts
VUE-5When KeepAlive deactivates a popup, the popup keeps its open state. It releases the scroll lock, the modal marks, the document listeners and the timers. The portal element of the popup leaves the document. When KeepAlive activates the popup again, the popup takes them back, and the same portal element returns.packages/react/src/utils/popups/portal/FloatingPortal.tsx
VUE-6Two copies of the library on one page share one scroll-lock count, one set of modal marks and one Escape stack.packages/utils/src/useScrollLock.ts
VUE-7When hydration ends and the pointer is over a trigger that opens on hover, the popup opens.packages/react/src/navigation-menu/trigger/NavigationMenuTrigger.tsx
VUE-8Grid navigation gives an item that is wider than the grid the width of the grid, in each build. A development build also reports the item. It uses the whole part of a number of columns. It uses 1 for a number of columns that is below 1 or not a finite number, and for an item width or an item height that is not a finite number. For these values, no build stays in a loop that does not end.packages/react/src/internals/composite/listIndex.ts
VUE-9Between the server HTML and the mount of its last item, a composite does not have two tab stops. While the server HTML has the tab stop on an item that is not mounted, the mounted items do not take it.packages/react/src/internals/composite/item/useCompositeItem.ts
VUE-10The check of an event target reads the disabled state of the innermost trigger that contains the target, in each order of registration. Base UI reads the first trigger of the map that contains the target. An outer trigger that registered first then decides for a target in an inner trigger that registered later.packages/react/src/utils/popups/element.ts
VUE-11When the active control of a field goes away, the field uses the control that was active before it and is still there. The same occurs when the active control is disabled and when KeepAlive deactivates it. The field has no control only when none is left.packages/react/src/internals/field-register-control/useFieldControlRegistration.ts
VUE-12When two panels of one collapsible are mounted, the trigger names the panel that registered last in aria-controls. When that panel unmounts, the trigger names the panel that stays. Base UI gives the trigger no aria-controls then, because the panel that stays does not register again.packages/react/src/collapsible/panel/CollapsiblePanel.tsx
VUE-13Form follows a change that the consumer makes in place to a reactive errors object, such as a new key. Base UI sees only a new object. Form watches the prop deeply and keeps a new plain copy for each change.packages/react/src/form/Form.tsx
VUE-14A tab names the id of its panel in aria-controls, also when the panel has an id of its own. Base UI registers the generated id of the panel, so aria-controls names no element when the consumer gives the panel an id.packages/react/src/tabs/panel/TabsPanel.tsx
VUE-15When two triggers of one item are mounted, the panel names the trigger that registered last in aria-labelledby. When that trigger unmounts, the panel names the trigger that stays. Base UI gives the panel no aria-labelledby then, because the trigger that stays does not register again.packages/react/src/accordion/panel/AccordionPanel.tsx
VUE-16When the id of a control changes, the control gets the aria-labelledby of the native <label> that names the new id, in each browser. Base UI reads labels of the hidden input, and WebKit keeps that list as it was before the change.packages/react/src/internals/labelable-provider/useAriaLabelledBy.ts
VUE-17The server HTML of a control in a field has the id of the label in aria-labelledby and the ids of the messages in aria-describedby, in each order of the parts. A control with no label has no aria-labelledby. Base UI adds these attributes after the page hydrates.packages/react/src/internals/labelable-provider/LabelableProvider.tsx
VUE-18A panel with an empty id has the id that its item generates. The open trigger names that id in aria-controls. Base UI gives the panel id="" then, so aria-controls names no element.packages/react/src/accordion/panel/AccordionPanel.tsx
VUE-19tabbable() leaves out a details, audio[controls], video[controls] or contenteditable element that has tabindex="-1", because the Tab key skips it. Base UI lists it. A tabindex value that is not an integer counts as no attribute.packages/react/src/utils/popups/focus/tabbable.ts
VUE-20A portal follows a container that is a ref or a getter. When it gives another element, the portal moves its portal element there and does not mount the popup again. When it gives null, the portal uses its fallback container. Base UI reads a ref object one time.packages/react/src/utils/popups/portal/FloatingPortalLite.tsx
VUE-21A native form reset removes the error of the field. Field.Control, Switch.Root, Checkbox.Root, CheckboxGroup, NumberField.Root, RadioGroup, OTPField.Root, Select.Root, Slider.Root, Combobox.Root and Autocomplete.Root do this after each reset that they follow, also when their value does not change. Each part cancels the pending validation and removes the message that the field put on the input. Each part also clears the validity of the field and the error of the form for the field. The change of a reset starts no validation. Base UI keeps the error that the field showed before the reset. Its controls do not listen for a reset, and a reset sends no input event.packages/react/src/field/control/FieldControl.tsx
VUE-22Triggers can join an open popup that has no active trigger, and none of them claims it. A mount of triggers that claim nothing does this, and so does an activation by KeepAlive. The popup then takes the first trigger of its map that is in the document. Base UI takes a trigger there only when it is the only one. Base UI has no counterpart of KeepAlive.packages/react/src/utils/popups/popupRoot.tsx
VUE-23Each Field.Label has the id of its id prop, or an id of its own, and the id follows the prop. The control names the last label in aria-labelledby. Base UI gives each label the id of the last label that registered. Two labels of one field then have the same id, and a change of the id prop has no effect.packages/react/src/field/label/FieldLabel.tsx
VUE-24A trigger that gets disabled stops its open delay, its rest delay and its safe polygon. Base UI keeps the timer, so the popup opens when the delay ends. The owner of a Tooltip then hears openChange(true) and openChange(false) with the reason disabled, for a popup that never shows.packages/react/src/utils/popups/interactions/useHoverTriggerInteraction.ts
VUE-25The hover intent opens the popup for the innermost trigger that contains the event target, in each order of registration. Base UI takes the first trigger of the map that contains the target. An outer trigger that registered first then gets the popup for a target in an inner trigger that registered later.packages/react/src/utils/popups/interactions/hoverIntent.ts
VUE-26When KeepAlive deactivates a trigger, the trigger stops its timers and its safe polygon. A popup that hover opened and that the trigger anchors then closes with the reason trigger-hover. This is the exception to the open state that a popup keeps under KeepAlive. KeepAlive sends no leave event, so the popup would stay open after the activation with no pointer on its trigger. Base UI has no counterpart of KeepAlive.packages/react/src/utils/popups/interactions/useHoverTriggerInteraction.ts
VUE-27A pointerdown whose pointer the browser does not know, such as an event that a script dispatched, still starts and ends a drag. Slider.Control calls setPointerCapture in a try block, because Firefox throws NotFoundError for such a pointer. Base UI has no guard there. The throw then stops the handler before it adds the listeners that end the drag.packages/react/src/slider/thumb/SliderThumb.tsx
VUE-28Slider.Control reads the computed style of its element again after the element changes, for example when as changes. Base UI reads the style one time and keeps it. The kept style belongs to an element that left the document, and a browser gives such a style no values. Base UI then reads the border and the padding of the control as 0, and a press on a control that has them gives a wrong value.packages/react/src/slider/thumb/SliderThumb.tsx
VUE-29The server HTML of a range slider has the index, the value and the text of the value of each thumb, also when the thumbs have no index prop. A thumb takes its index from the order in which the thumbs render. Base UI needs the index prop on each thumb for a server render, because its list of thumbs fills only after the mount. The server HTML of a slider that has Slider.Label links the label. The root has the id of the label in aria-labelledby. The input of each thumb that has no name of its own has it too. The label can come before or after the control. Base UI links the label after the page hydrates.packages/react/src/slider/thumb/SliderThumb.tsx
VUE-30close() of a toast store reads no document while the store has no viewport element. A call in a server render, or before the viewport is mounted, thus closes the toast. Base UI reads the global document before it reads the viewport, so the same call throws in Node.packages/react/src/toast/store.ts
VUE-31A trigger that gets disabled, or that moves to another store, stops its open delay. Base UI keeps the timer until the trigger unmounts, so the popup opens when the delay ends, also for a trigger that is disabled or that has another store.packages/react/src/utils/popups/interactions/useFocus.ts
VUE-32When KeepAlive deactivates a trigger, the trigger stops its open delay. A popup that focus opened and that the trigger anchors then closes with the reason trigger-focus. This is the exception to the open state that a popup keeps under KeepAlive. The focused trigger leaves the document, and Firefox and WebKit send no focusout for it, so the popup would stay open after the activation with no focus on its trigger. Base UI has no counterpart of KeepAlive.packages/react/src/utils/popups/interactions/useFocus.ts
VUE-33A previousFocusableElement or nextFocusableElement that is a ref or a getter with no element is the same as null. When the Tab key leaves the popup, the focus then goes to the outside guard of the portal, which moves it on. Base UI falls back only when the prop itself is empty. A ref object with no current moves no focus there, and the focus stays on a hidden guard of the popup.packages/react/src/utils/popups/focus/FloatingFocusManager.tsx
VUE-34isOpen of a popup handle is reactive. A computed, a watch or a template that reads it follows the open state of the popup, and the root that controls the handle. In Base UI, a component that reads isOpen in its render does not render again when the popup opens or closes.packages/react/src/tooltip/store/TooltipHandle.ts
VUE-35CheckboxGroup follows a change that the consumer makes in place to a reactive value array, such as push or splice. The checkboxes, the state of the field and the validation get the new value. Base UI sees only a new array. The part reads a copy of the array, and the copy reads each item.packages/react/src/checkbox-group/CheckboxGroup.tsx
VUE-36The label of an item can be a function that returns the content of the label, so one label can show in the value part and in its item at the same time. The text of such an item is the result of itemToStringLabel, or the text of its value. Base UI takes a React element as a label, and the text of that item is [object Object].packages/react/src/internals/resolveValueLabel.tsx
VUE-37The scroll lock reads the scrollbar width from the window of the document that it locks. Base UI gives the document to ownerWindow, which returns the window of the page. For a frame, Base UI then compares the frame with the page. It takes the way for scrollbars that take space also when the frame has overlay scrollbars.packages/utils/src/useScrollLock.ts
VUE-38The picture of the old content is the DOM at the time of the trigger change. It has what a component in the content changed by itself. Base UI clones the content after each render of the viewport, so a change that no render of the viewport followed is not in its picture.packages/react/src/utils/popups/viewport/usePopupViewport.tsx
VUE-39The content of the new trigger mounts one time for a change of the active trigger, when the trigger gives its payload with the change. Base UI mounts it two times: the key of the content has the id of the trigger, and a layout effect of the same change raises the count in the key.packages/react/src/utils/popups/viewport/usePopupViewport.tsx
VUE-40The picture of the old content has no id on an HTML element and no name on a control. Two elements with one id then never exist during a morph, so aria-labelledby of the popup names the live title. A checked radio of the picture does not uncheck the live radio. Base UI keeps both in its picture.packages/react/src/utils/popups/viewport/usePopupViewport.tsx
VUE-41Each request of the frame scheduler runs its callback when requestAnimationFrame calls back at once. The scheduler sets its flag before it calls requestAnimationFrame. Base UI sets the flag after the call. tick clears the flag inside the call, and Base UI then sets it again. Each later request finds the flag set and never runs its callback.packages/utils/src/useAnimationFrame.ts
VUE-42A Checkbox.Root that has no value and no name, in a CheckboxGroup that has allValues, shows its own state. Base UI shows the checked prop of such a checkbox. After a click, its aria-checked stays false while its input is on.packages/react/src/checkbox-group/useCheckboxGroupParent.ts
VUE-43The node of a popup in the popup tree has the positioning context of the popup only while the popup is at that node. The node loses the context when the popup moves to another node or to another tree, when the positioner of the popup unmounts, and while KeepAlive holds the positioner. Base UI leaves the context of the last render on the node. A popup above that node then takes the popup for an open child, also after the popup closed or moved.packages/react/src/utils/popups/positioning/useFloating.ts
VUE-44With no locale, the filters of Combobox.useFilter, Autocomplete.useFilter, Combobox.Root and Autocomplete.Root use en-US until their component is mounted, and then the runtime locale. A locale that the developer gives applies from the first render, on the server and in the browser alike. A list that a server filtered then hydrates with no mismatch. With no locale, Base UI uses the runtime locale in each render, so a server and a browser can filter a list in different ways.packages/react/src/combobox/root/utils/useFilter.ts
VUE-45When two titles of one dialog or of one popover are mounted, the popup names the title that registered last in aria-labelledby. When that title unmounts, the popup names the title that stays. Base UI gives the popup no aria-labelledby then, because the title that stays does not write its id again. The descriptions follow the same rule for aria-describedby.packages/react/src/dialog/title/DialogTitle.tsx
VUE-46A key that the list of a child popup does not stop goes to the list of the parent popup one time, also when Teleport moved the child popup. A close key of the child list that is also a navigation key of the parent list then closes the child list and moves the highlight of the parent list.packages/react/src/utils/popups/interactions/useListNavigation.ts
VUE-47With restoreFocus, the focus manager moves the focus back into the popup when the focused element in the popup is removed, in each engine. Firefox and WebKit send no focusout for the removal, so a MutationObserver on the popup element also starts the restore.packages/react/src/utils/popups/focus/FloatingFocusManager.tsx
VUE-48A popup that unmounts leaves the timer of its delay group as it is. In Base UI, a closed popup that another popup replaced in the group clears the timer of that other popup when it unmounts. The group then stays active until a popup opens and closes again. Until then, each popup of the group opens with no delay and with no animation.packages/react/src/utils/popups/delay-group/FloatingDelayGroup.tsx
VUE-49The details of the openChange event of ContextMenu.Root have the type of preventUnmountOnClose(). Base UI types the details of onOpenChange without that function, while the object has it and the text of the unmount action tells the developer to call it.packages/react/src/context-menu/root/ContextMenuRoot.tsx
VUE-50A toast swipe reports no error when the browser refuses to capture the pointer. Firefox throws NotFoundError from setPointerCapture when the pointer id is not an active pointer, such as the pointer id of a dispatched event. Vase UI catches the error, and the swipe goes on. In Base UI the error leaves the pointerdown handler.packages/react/src/toast/root/ToastRoot.tsx
VUE-51The server HTML of Select.Trigger and Combobox.Trigger has the id of the label part of the family in aria-labelledby, in each order of the two parts. Base UI adds the attribute after the page hydrates.packages/react/src/select/trigger/SelectTrigger.tsx
VUE-52Select.Value follows a change that the consumer makes in place to a reactive items prop of Select.Root, such as a new key. Base UI sees only a new object. The root watches the prop deeply and keeps a new plain copy for each change.packages/react/src/select/root/SelectRoot.tsx
VUE-53When KeepAlive deactivates a scrub area during a scrub, the scrub ends with no commit. The root loses data-scrubbing, the cursor goes out of the document and the pointer lock ends. After the activation, a pointer release commits nothing. Under <Activity>, Base UI ends the pointer lock and clears the scrubbing state of the root. The area keeps its own scrubbing state, so it shows its cursor again after the activation, and the next pointer release commits the value.packages/react/src/number-field/scrub-area/NumberFieldScrubArea.tsx
VUE-54When the active item of a composite changes while the focus is outside the composite, the tab stop moves to that item. A native reset, a controlled value that the parent changes, and an active item that mounts late are such changes. When such a change leaves no active item, or an active item that is disabled or hidden, the tab stop moves to the first enabled item. When the focus leaves the composite, the tab stop goes back to the active item. While the composite has the focus, the tab stop stays on the item that the user chose. The Tab key thus enters a Radio Group on the checked radio, and a Tabs list with manual activation on the active tab. In Base UI, only Tabs.Tab moves the tab stop, and only to a tab that becomes active. A Radio Group keeps the tab stop on the radio that had the focus last, and a Tabs list keeps it on the tab that had the focus last or that was active last.packages/react/src/internals/composite/root/useCompositeRoot.ts
VUE-55A root provides the tree that its popup uses. A detached trigger can give the root another tree. A part in the popup of the root then registers in the new tree, so a menu that a trigger in the popup opens closes with the root. Base UI provides the first tree of the root and never changes it. A part in the popup then registers in a tree that the popup does not read, and the menu that its trigger opens stays open.packages/react/src/utils/popups/tree/FloatingTree.tsx
VUE-56When two titles of one toast are mounted, the toast names the title that registered last in aria-labelledby. When that title unmounts, the toast names the title that stays. Base UI gives the toast no aria-labelledby then, because the title that stays does not write its id again. The descriptions follow the same rule for aria-describedby.packages/react/src/toast/utils/useToastLabelPart.ts
VUE-57When Drawer.SwipeArea unmounts during a gesture that opens the drawer, it removes the swipe movement, data-swiping and transition: none from the popup. It also removes the swipe progress from the backdrop and from Drawer.Provider. The drawer is then fully open. In Base UI, the swipe area only lets an outside press close the drawer again. The popup then stays at the position of the gesture, and the indent stays at the progress of the gesture.packages/react/src/drawer/swipe-area/DrawerSwipeArea.tsx
VUE-58A listener of the consumer on Drawer.Viewport runs before the swipe listener of the viewport that has the same key, and event.preventVaseUIHandler() in it stops that swipe listener. A consumer can thus stop the start of a swipe, as it can stop the handler of each other part. In Base UI, the listener of the viewport runs first, and a listener of the consumer cannot stop it.packages/react/src/drawer/viewport/DrawerViewport.tsx
VUE-59A valueChange listener that calls details.cancel() stops the change of an uncontrolled Autocomplete.Root. The input and Autocomplete.Value keep the old text, and the root emits no update:value. Base UI writes its state before it calls onValueChange, so a canceled change still changes an uncontrolled autocomplete.packages/react/src/autocomplete/root/AutocompleteRoot.tsx
VUE-60A trigger that has focus guards beside its element has one root node. NavigationMenu.Viewport in a positioner has one root node too. A rule of <style scoped>, v-show, a custom directive and <Transition> of the consumer thus apply to the element of the part, also while the guards are in the document.packages/react/src/navigation-menu/trigger/NavigationMenuTrigger.tsx
VUE-61Menu.Positioner, Popover.Positioner, Select.Positioner and Combobox.Positioner have one root node, also while their popup is modal: Menu.Portal, Popover.Portal, Select.Portal and Combobox.Portal render the internal backdrop of a modal popup. A rule of <style scoped>, v-show and a custom directive of the consumer thus apply to the element of the positioner. Autocomplete.Portal and Autocomplete.Positioner are the parts of Combobox under other names. In Base UI, the positioner renders the backdrop beside its element.packages/react/src/menu/positioner/MenuPositioner.tsx
VUE-62While Drawer.VirtualKeyboardProvider holds the space for the keyboard on a scroll container, it watches the style attribute of that element. When a render or a script replaces a declaration of the provider, the provider keeps the new value for the restore and writes its declaration again before the next frame. In Base UI, a new padding-bottom of the consumer replaces the space until the next alignment, and the restore then writes the value from before the keyboard over it.packages/react/src/drawer/virtual-keyboard-provider/DrawerVirtualKeyboardProvider.tsx
VUE-63A popup that is not modal can stay open when a guard of its trigger asks for the close, for example when its open prop does not change. Tab from the trigger then moves the focus to the elements of the popup, and Tab from the last of them moves it to the element after the trigger. Shift+Tab from the trigger moves the focus to the element before the trigger. Tab from the trigger skips a popup with no tabbable element. The trigger keeps the focus only when no other element is tabbable. The search for the next element skips the guards of the trigger and the content of the popup. In Base UI, the search can give a guard of the portal, and that guard sends the focus back into the popup. When the popup has no tabbable element, the guards call focus() on each other in the same call stack, and no handler ends the sequence. A popup that has guards beside its trigger has no guards at the place of its own portal (VUE-66), so the search cannot give one.packages/react/src/utils/popups/useTriggerFocusGuards.ts
VUE-64A popup root in a pending branch of <Suspense> does not attach its store to its handle. The handle, and each detached trigger, stay with the root that is mounted. The root attaches when Vue resolves the branch, before the onMounted hook of each part below it. A branch that Vue drops never attaches. Base UI has this rule for a render that React does not commit.packages/react/src/utils/popups/popupRoot.tsx
VUE-65Combobox.createItems gives getValue and getLabel the leaf item of grouped data, and the result has the type of the leaf item. This holds with TypeScript 5.9 and 6.0. With these versions, the order of the members of the data type of Base UI gives the group as the item, so such a call does not type-check there. TypeScript 7.0 accepts both orders.packages/react/src/combobox/items/createItems.ts
VUE-66A popup that is not modal and stays open has one place in the tab order, right after its trigger, while its trigger has focus guards. The Tab key goes from the element before the trigger to the trigger, to the elements of the popup, and to the element after the trigger. Shift+Tab goes the other way. A menu goes from any element of its popup to the trigger for Shift+Tab, as in Base UI. This holds when the portal is beside the trigger, before it or detached. A popup with no tabbable element is skipped in both directions. The guard before the trigger sends a focus from any other element to the trigger when the popup stays open. The guard after the trigger sends a focus from the trigger, or from no element, to the start of the popup, and a focus from another element outside the popup to the end of the popup. The portal then renders no guards of its own. A focus that comes in through the last inside guard does not stop the return of the focus, so Escape from inside the popup returns the focus to the trigger. In Base UI, Tab from the element before the trigger stays on that element. A detached portal keeps the focus at the element after the trigger, or between that element and the popup. Base UI also sets the flag that stops the return of the focus before it tests where the focus comes from, so a focus that comes in through the last inside guard stops the return of the focus at the next close.packages/react/src/utils/popups/useTriggerFocusGuards.ts
VUE-67In Safari on a Mac, a focus with no related target opens the popup of a trigger only when the last input of the window was a key. Each trigger records that input while it is mounted, also while it is not enabled. Base UI records it only while the trigger is enabled, and it assumes a key before the first record. A trigger of a menubar is enabled only while a menu of the menubar is open, so it misses the press that opened the menu. A hover on the next trigger then opens the next menu, the first menu gives the focus back to its trigger, and that focus opens the first menu again. Both menus then close.packages/react/src/utils/popups/interactions/useFocus.ts

Components of Vase UI's own ​

A component of Vase UI's own is a component that Base UI does not have. Its behavior follows a standard, and its API follows the convention of the families. parity/own holds one record for each component.

None yet.

Not ported ​

parity/scope.json lists what Vase UI does not port, each with its reason.

WhatReason
filter-dropdown as a public entryBase UI has no package export, no index file and no docs page for it. Vase UI ports it only as the internal dependency of Menu.
the 35 ./internals/* entry pointsBase UI does not document them. Vase UI ports the code that a component needs as internal modules and exports none of them.
the temporal adaptersNo Base UI component imports them at the tracked commit.
createSelector and createSelectorMemoizedNo Base UI component imports them. Vue computed does this work.
StoreInspectorA React development panel. No component imports it.
the React 17 and 18 shimsThey exist only to support old React versions.
Accordion loopFocus and orientation propsDeprecated upstream; they have no effect.
Context Menu positionMethod and closeParentOnEsc propsDeprecated upstream; "This prop has no effect on Context Menu."