Description
Mounting any <Tabs> throws an uncaught promise rejection on mount:
Uncaught (in promise) TypeError: Failed to execute 'observe' on 'ResizeObserver': parameter 1 is not of type 'Element'.
at useResizeObserver (@vueuse/core)
at setup (reka-ui TabsIndicator)
The tabs still render and switch — only the sliding indicator's initial measurement fails — but the error fires on every Tabs instance, so the console fills with it (one per tabbed view/modal). Reproduces consistently across every Tabs usage in our app.
Environment
frappe-ui: 1.0.0-beta.9
reka-ui: 2.10.0 (frappe-ui requires ^2.5.0)
@vueuse/core: 14.3.0 (resolved under reka-ui; reka requires ^14.1.0)
- Vue 3 + Vite
Root cause
reka-ui's TabsIndicator does:
useResizeObserver(computed(() => [context.tabsList.value, ...tabs.value]), updateIndicatorStyle)
context.tabsList is reka's currentElement (from useForwardExpose()). On the immediate (flush: 'post') run during mount, it resolves to a truthy non-Element node before the TabsList element is settled. @vueuse@14.3.0's useResizeObserver only guards falsy targets:
for (const _el of els) if (_el) observer.observe(_el, observerOptions)
So a truthy non-Element passes if (_el) and reaches observer.observe(...), which throws parameter 1 is not of type 'Element'.
Suggested fix
In Tabs.vue (or by constraining what's passed to the observer), either:
- filter the observed targets to real elements, e.g.
el instanceof Element, or
- defer the indicator's
useResizeObserver until isMounted is true and an active tab element exists.
Possibly related
Tabs.vue sets :default-value="props.tabs[0].label" while TabsTrigger/TabsContent are keyed by array index (:value="i"). So when used without v-model, the default value (a label string) matches no trigger value (a number), and no tab is active by default — which may be what leaves the indicator without a valid element to observe on the first tick.
Minimal reproduction
<Tabs v-model="tabIndex" :tabs="[{ label: 'A' }, { label: 'B' }]">
<template #tab-panel="{ tab }">{{ tab.label }}</template>
</Tabs>
Open the console on mount.
Description
Mounting any
<Tabs>throws an uncaught promise rejection on mount:The tabs still render and switch — only the sliding indicator's initial measurement fails — but the error fires on every
Tabsinstance, so the console fills with it (one per tabbed view/modal). Reproduces consistently across everyTabsusage in our app.Environment
frappe-ui:1.0.0-beta.9reka-ui:2.10.0(frappe-ui requires^2.5.0)@vueuse/core:14.3.0(resolved underreka-ui; reka requires^14.1.0)Root cause
reka-ui'sTabsIndicatordoes:context.tabsListis reka'scurrentElement(fromuseForwardExpose()). On the immediate (flush: 'post') run during mount, it resolves to a truthy non-Elementnode before theTabsListelement is settled.@vueuse@14.3.0'suseResizeObserveronly guards falsy targets:So a truthy non-
Elementpassesif (_el)and reachesobserver.observe(...), which throwsparameter 1 is not of type 'Element'.Suggested fix
In
Tabs.vue(or by constraining what's passed to the observer), either:el instanceof Element, oruseResizeObserveruntilisMountedis true and an active tab element exists.Possibly related
Tabs.vuesets:default-value="props.tabs[0].label"whileTabsTrigger/TabsContentare keyed by array index (:value="i"). So when used withoutv-model, the default value (a label string) matches no trigger value (a number), and no tab is active by default — which may be what leaves the indicator without a valid element to observe on the first tick.Minimal reproduction
Open the console on mount.