@@ -149,7 +149,7 @@ export interface SelectSlots<
149149150150<script setup lang="ts" generic="T extends ArrayOrNested<SelectItem>, VK extends GetItemKeys<T> = 'value', M extends boolean = false, Mod extends Omit<ModelModifiers, 'lazy'> = Omit<ModelModifiers, 'lazy'>">
151151import { useTemplateRef, computed, onMounted, toRef } from 'vue'
152-import { SelectRoot, SelectArrow, SelectTrigger, SelectPortal, SelectContent, SelectLabel, SelectGroup, SelectItem as RSelectItem, SelectItemIndicator, SelectItemText, SelectSeparator, useForwardPropsEmits } from 'reka-ui'
152+import { SelectRoot, SelectArrow, SelectTrigger, SelectPortal, SelectContent, SelectViewport, SelectValue as RSelectValue, SelectLabel, SelectGroup, SelectItem as RSelectItem, SelectItemIndicator, SelectItemText, SelectSeparator, useForwardPropsEmits } from 'reka-ui'
153153import { defu } from 'defu'
154154import { reactivePick } from '@vueuse/core'
155155import { useAppConfig } from '#imports'
@@ -181,7 +181,11 @@ const uiProp = useComponentUI('select', props)
181181182182const rootProps = useForwardPropsEmits(reactivePick(props, 'open', 'defaultOpen', 'disabled', 'autocomplete', 'required', 'multiple'), emits)
183183const portalProps = usePortal(toRef(() => props.portal))
184-const contentProps = toRef(() => defu(props.content, { side: 'bottom', sideOffset: 8, collisionPadding: 8, position: 'popper' }) as SelectContentProps)
184+// Resolve `position` from props > `app.config.ts` `defaultVariants` > hardcoded default,
185+// so both the template logic (`isItemAligned`) and the Reka UI primitive see the same value.
186+// `tv()` only applies `defaultVariants` to classes, not to runtime logic (see #6360).
187+const position = computed(() => props.content?.position ?? appConfig.ui?.select?.defaultVariants?.position ?? 'popper')
188+const contentProps = toRef(() => defu(props.content, { side: 'bottom', sideOffset: 8, collisionPadding: 8, position: position.value }) as SelectContentProps)
185189const arrowProps = toRef(() => defu(props.arrow, { rounded: true }) as SelectArrowProps)
186190187191const { emitFormChange, emitFormInput, emitFormBlur, emitFormFocus, size: formFieldSize, color, id, name, highlight, disabled, ariaAttrs } = useFormField<InputProps>(props)
@@ -190,6 +194,8 @@ const { isLeading, isTrailing, leadingIconName, trailingIconName } = useComponen
190194191195const selectSize = computed(() => fieldGroupSize.value || formFieldSize.value)
192196197+const isItemAligned = computed(() => position.value === 'item-aligned')
198+193199const ui = computed(() => tv({ extend: tv(theme), ...(appConfig.ui?.select || {}) })({
194200 color: color.value,
195201 variant: props.variant,
@@ -198,7 +204,8 @@ const ui = computed(() => tv({ extend: tv(theme), ...(appConfig.ui?.select || {}
198204 highlight: highlight.value,
199205 leading: isLeading.value || !!props.avatar || !!slots.leading,
200206 trailing: isTrailing.value || !!slots.trailing,
201- fieldGroup: orientation.value
207+ fieldGroup: orientation.value,
208+ position: position.value
202209}))
203210204211const groups = computed<SelectItem[][]>(() =>
@@ -289,7 +296,10 @@ const viewportRef = useTemplateRef('viewportRef')
289296290297defineExpose({
291298 triggerRef: toRef(() => triggerRef.value?.$el as HTMLButtonElement),
292- viewportRef: toRef(() => viewportRef.value)
299+ viewportRef: toRef(() => {
300+ const instance = viewportRef.value
301+ return (instance && typeof instance === 'object' && '$el' in instance ? instance.$el : instance) as HTMLElement | null
302+ })
293303})
294304</script>
295305@@ -320,16 +330,16 @@ defineExpose({
320330</slot>
321331</span>
322332323-<slot :model-value="(modelValue as ApplyModifiers<GetModelValue<T, VK, M, ExcludeItem>, Mod>)" :open="open" :ui="ui">
324-<template v-for="displayedModelValue in [displayValue(modelValue as any)]" :key="displayedModelValue">
325-<span v-if="displayedModelValue !== undefined && displayedModelValue !== null" data-slot="value" :class="ui.value({ class: uiProp?.value })">
326- {{ displayedModelValue }}
327- </span>
328-<span v-else data-slot="placeholder" :class="ui.placeholder({ class: uiProp?.placeholder })">
329- {{ placeholder ?? ' ' }}
330-</span>
331-</template>
332-</slot>
333+<template v-for="displayedModelValue in [displayValue(modelValue as any)]" :key="displayedModelValue">
334+<RSelectValue
335+:data-slot="displayedModelValue != null ? 'value' : 'placeholder'"
336+:class="displayedModelValue != null ? ui.value({ class: uiProp?.value }) : ui.placeholder({ class: uiProp?.placeholder })"
337+>
338+<slot :model-value="(modelValue as ApplyModifiers<GetModelValue<T, VK, M, ExcludeItem>, Mod>)" :open="open" :ui="ui">
339+ {{ displayedModelValue ?? (placeholder ?? ' ') }}
340+</slot>
341+</RSelectValue>
342+</template>
333343334344<span v-if="isTrailing || !!slots.trailing" data-slot="trailing" :class="ui.trailing({ class: uiProp?.trailing })">
335345<slot name="trailing" :model-value="(modelValue as ApplyModifiers<GetModelValue<T, VK, M, ExcludeItem>, Mod>)" :open="open" :ui="ui">
@@ -343,7 +353,7 @@ defineExpose({
343353<SelectContent data-slot="content" :class="ui.content({ class: uiProp?.content })" v-bind="contentProps">
344354<slot name="content-top" />
345355346-<div ref="viewportRef" role="presentation" data-slot="viewport" :class="ui.viewport({ class: uiProp?.viewport })">
356+<component :is="isItemAligned ? SelectViewport : 'div'" ref="viewportRef" role="presentation" data-slot="viewport" :class="ui.viewport({ class: uiProp?.viewport })">
347357<SelectGroup v-for="(group, groupIndex) in groups" :key="`group-${groupIndex}`" data-slot="group" :class="ui.group({ class: uiProp?.group })">
348358<template v-for="(item, index) in group" :key="`group-${groupIndex}-${index}`">
349359<SelectLabel v-if="isSelectItem(item) && item.type === 'label'" data-slot="label" :class="ui.label({ class: [uiProp?.label, item.ui?.label, item.class] })">
@@ -400,7 +410,7 @@ defineExpose({
400410</RSelectItem>
401411</template>
402412</SelectGroup>
403-</div>
413+</component>
404414405415<slot name="content-bottom" />
406416