Reka UI reka-ui@2.10.5
Unstyled, accessible component primitives for Vue 3. Requires vue >= 3.4.0
(prepared source package.json:87-89). Docs: https://reka-ui.com
References
- API surface: entry points, every component part, utilities.
- Composition:
asChild, prop forwarding, context injection, controlled state. - Styling and animation:
data-state,--reka-CSS variables,force-mountwith<Transition>. - New and changed components: Drawer, Autocomplete, Color primitives, Month/Year pickers, and version-specific prop changes.
- Integrations: namespaced entry, Nuxt module, component resolver, dates with
@internationalized/date, virtualization.
Setup
pnpm add reka-ui # or npm / yarn / bun
<script setup lang="ts">
import { DialogRoot, DialogTrigger, DialogPortal, DialogOverlay, DialogContent, DialogTitle } from 'reka-ui'
</script>
<template>
<DialogRoot>
<DialogTrigger>Edit profile</DialogTrigger>
<DialogPortal>
<DialogOverlay />
<DialogContent>
<DialogTitle>Edit profile</DialogTitle>
</DialogContent>
</DialogPortal>
</DialogRoot>
</template>
API changes (2.10.x and 2.9.x)
Prioritized recent releases. Baseline skill covered up to 2.9.7.
- NEW
Drawerprimitive (2.10.0): swipe dismiss, snap points, nested drawers. Parts:DrawerRoot/Trigger/Portal/Overlay/Content/Close/Title/Description/Handle/SwipeArea/Viewport/Indent/IndentBackground(prepared sourcesrc/Drawer/). Release: https://github.com/unovue/reka-ui/releases/tag/v2.10.0 - NEW
ConfigProviderteleportToprop: global default teleport target (prepared sourcesrc/ConfigProvider/ConfigProvider.vue:45) - NEW
DialogRootunmountOnHideprop, defaulttrue; setfalseto keep content mounted when hidden (prepared sourcesrc/Dialog/DialogRoot.vue:20) - NEW
SelectRootnullableValueprop for a hidden-input value representing the empty selection (prepared sourcesrc/Select/SelectRoot.vue:18) - NEW
HoverCardRootenableTouchprop, defaultfalse(prepared sourcesrc/HoverCard/HoverCardRoot.vue:15) - NEW
DateFieldRootstepSnappingprop, defaultfalse(prepared sourcesrc/DateField/DateFieldRoot.vue:57) - NEW
TreeItemdisabledprop (2.10.0): https://github.com/unovue/reka-ui/releases/tag/v2.10.0 - NEW
TabsIndicatorexposes--reka-tabs-indicator-size,--reka-tabs-indicator-thickness,--reka-tabs-indicator-positionCSS variables (prepared sourcesrc/Tabs/TabsIndicator.vue:73-75) - Better type inference for
useEmitAsPropsanduseForwardPropsEmits(2.10.0) - NEW
Autocompletecomponent (2.9.0), a Combobox-style input with its ownAutocomplete*part family. Docs: https://reka-ui.com/docs/components/autocomplete - NEW Color primitives (2.9.0):
ColorArea*,ColorField*,ColorSlider*,ColorSwatch,ColorSwatchPicker*, plus color parse/convert utilities exported from the root - NEW
TimeRangeField(2.9.0):TimeRangeFieldRoot,TimeRangeFieldInput - NEW Month and Year pickers (2.9.0):
MonthPicker*,YearPicker*andMonthRangePicker*,YearRangePicker*families - NEW
CheckboxRoot/SwitchRootcustom boolean values:trueValueandfalseValueprops replace the fixedtrue/false(prepared sourcesrc/Checkbox/CheckboxRoot.vue:27-31) - NEW
DropdownMenuFilterpart for searchable dropdown menus (2.9.0) - NEW
Splitterpixel sizing and constraints (2.9.0) - NEW global tooltip content configuration via
TooltipProvider(2.9.0) - Menu internals exported from
reka-ui/internal; unstable, may change without semver (prepared sourcesrc/internal.ts:1-7)
Earlier breaking changes still relevant when touching older code:
radix-vuerenamed toreka-ui; CSS variables use--reka-prefix and data attributes usedata-reka-. Migration: https://reka-ui.com/docs/guides/migration- Combobox refactor:
filterFunctionprop removed;searchTermanddisplayValuemoved from Root toComboboxInput(migration guide above) Checkbox,Toggle,MenuCheckboxItemuse standardv-modelinstead ofv-model:checked/v-model:pressed(migration guide above)PaginationRootitemsPerPageis required (migration guide above)weekStartsOnon Calendar/DatePicker is locale-independent since 2.8.0: https://github.com/unovue/reka-ui/releases/tag/v2.8.0
Release index: https://github.com/unovue/reka-ui/releases
Best practices
- Compose with
asChild: render a Reka primitive as your own element or component while keeping behavior and accessibility (https://reka-ui.com/docs/guides/composition)
<TooltipTrigger asChild>
<MyButton>Hover me</MyButton>
</TooltipTrigger>
- Build wrappers with
useForwardPropsEmitsso all props and emits pass through to the primitive (https://reka-ui.com/docs/utilities/use-forward-props-emits)
const props = defineProps<AccordionRootProps>()
const emits = defineEmits<AccordionRootEmits>()
const forwarded = useForwardPropsEmits(props, emits)
// <AccordionRoot v-bind="forwarded">
- Wrap the app in
ConfigProviderto setdir(RTL),locale,scrollBody, and ateleportTodefault (https://reka-ui.com/docs/utilities/config-provider)
<ConfigProvider dir="rtl" :scroll-body="false">
<App />
</ConfigProvider>
- Use
useForwardExposein fragment (multi-root) components so template refs return the target DOM element (https://reka-ui.com/docs/utilities/use-forward-expose)
const { forwardRef } = useForwardExpose()
// <div :ref="forwardRef">...</div>
- Style states via
data-stateattributes instead of toggling classes; use:deep()for teleported content in scoped styles (https://reka-ui.com/docs/guides/styling)
.AccordionItem[data-state="open"] { border-bottom-width: 2px; }
- Animate with
<Transition>by addingforce-mountto content parts and controlling unmount yourself (https://reka-ui.com/docs/guides/animation)
<Transition name="fade">
<DialogContent force-mount>...</DialogContent>
</Transition>
- Virtualize long lists with
ComboboxVirtualizer,ListboxVirtualizer,AutocompleteVirtualizer, orTreeVirtualizer; give the scroll container a fixed height (https://reka-ui.com/docs/guides/virtualization)
<ComboboxViewport class="max-h-80 overflow-y-auto">
<ComboboxVirtualizer :options="items" :estimate-size="25" v-slot="{ option }">
<ComboboxItem :value="option">{{ option.label }}</ComboboxItem>
</ComboboxVirtualizer>
</ComboboxViewport>
-
Access internal primitive state from custom children with
injectXContextfunctions such asinjectAccordionRootContext(https://reka-ui.com/docs/guides/inject-context) -
useIdfrom Reka UI resolves in order: a passed deterministic id, theConfigProvideruseIdsource, Vue's nativeuseId(Vue 3.5+), then a counter fallback (prepared sourcesrc/shared/useId.ts:26-34). On Nuxt with Vue below 3.5, pass Nuxt'suseIdthroughConfigProviderto avoid hydration id mismatches (https://reka-ui.com/docs/guides/server-side-rendering) -
Date and time components take
DateValueandTimeValueobjects from@internationalized/date(a direct dependency), never raw strings (https://reka-ui.com/docs/guides/dates)
Common gotchas
- Every part must sit under its Root; most components also need
*Contentinside a*PortalorTeleportfor correct stacking. PresenceforceMountrenders content regardless of open state; handle visibility yourself, for example with:hidden(https://reka-ui.com/docs/utilities/presence).- Hidden form fields use the part's
nameandvalueprops;SelectRootalso acceptsnullableValuefor the empty state. - Import from
reka-uifor tree-shaking, orreka-ui/namespacedfor grouped parts likeDialog.Root; see Integrations.