This commit is contained in:
Sebastien Powell 2026-10-05 15:35:31 +01:00
parent b7071c91c7
commit 32e47d2112
4 changed files with 30 additions and 1 deletions

View File

@ -847,4 +847,23 @@ describe('v2/components/Select', () => {
});
});
});
describe('portal', () => {
it('should keep the menu in place when teleported is false', async () => {
const wrapper = render(Select, {
props: {
items: [
{ value: 'Option 1', label: 'Option 1' },
{ value: 'Option 2', label: 'Option 2' },
],
defaultOpen: true,
teleported: false,
},
});
const { popover } = await getPopoverContainer(wrapper.getByTestId('select-trigger'));
expect(wrapper.container.contains(popover)).toBe(true);
expect(popover.parentElement).not.toBe(document.body);
});
});
});

View File

@ -79,6 +79,14 @@ export type SelectProps<M extends boolean = false> = Omit<
/** Additional CSS class(es) applied to the dropdown content container (portaled). */
contentClass?: string;
/**
* Render the menu in a portal on `document.body`.
* Set `false` inside a dialog so the menu stays in the dialog.
* A portaled menu sits outside a focus trap, and a dialog can treat a click on it as an outside click.
* @defaultValue true
*/
teleported?: boolean;
};
export type SelectEmits<M extends boolean = false> = Omit<SelectRootEmits, 'update:modelValue'> & {

View File

@ -58,6 +58,7 @@ const props = withDefaults(defineProps<SelectProps<M>>(), {
sideOffset: 4,
align: 'start',
clearable: false,
teleported: true,
});
const emit = defineEmits<SelectEmits<M>>();
defineSlots<SelectSlots<M>>();
@ -406,7 +407,7 @@ function resolveDisplayValue(value: unknown): string | undefined {
/>
</SelectTrigger>
<SelectPortal>
<SelectPortal :disabled="!teleported">
<SelectContent
data-test-id="select-content"
:class="[$style.selectContent, size, contentClass]"

View File

@ -89,6 +89,7 @@ Primitives, object values, and `valueKey` / `labelKey` mapping are intentionally
- `sideOffset?: number` Distance in pixels from the trigger. Default: `4`. The dropdown always opens below the trigger (`side` is not exposed).
- `align?: 'start' | 'center' | 'end'` Alignment of the dropdown against the trigger. Default: `start`. Use `end` to line the menu up with the trigger's end edge (the right edge in LTR).
- `contentClass?: string` Additional CSS class(es) applied to the dropdown content container (portaled).
- `teleported?: boolean` Render the menu in a portal on `document.body`. Default: `true`. Set `false` inside a dialog so the menu stays in the dialog. A portaled menu sits outside a focus trap, and a dialog can treat a click on it as an outside click.
**UI Props**