Placement
Source for this preview
---import {DEFAULT_PLACEMENT, PLACEMENT_OPTIONS} from '../../example-data';---
<div id="placement-demo" class="placement-stage" aria-label="Interactive placement selector"> { PLACEMENT_OPTIONS.map((placement) => ( <button type="button" class:list={[ 'placement-control', {'is-selected': placement === DEFAULT_PLACEMENT}, ]} value={placement} aria-pressed={placement === DEFAULT_PLACEMENT} aria-label={`Place floating element at ${placement}`} > <span aria-hidden="true"></span> </button> )) } <floating-root id="placement-root" open placement={DEFAULT_PLACEMENT}> <div slot="reference" class="placement-reference">Reference</div> <template slot="content"> <div class="placement-floating" role="status">{DEFAULT_PLACEMENT}</div> </template> </floating-root></div>
<script> import { FloatingRootElement, offset, type Placement, } from '@floating-ui-plus/web-components'; import {initializeExample} from './initialize-example';
initializeExample('placement', (scope) => { const floating = FloatingRootElement.query(scope, '#placement-root'); floating.middleware = [offset(18)]; const panel = scope.querySelector<HTMLElement>('.placement-floating'); const controls = [ ...scope.querySelectorAll<HTMLButtonElement>( '.placement-control', ), ];
controls.forEach((button) => { button.addEventListener('click', () => { const placement = button.value as Placement; floating.placement = placement; controls.forEach((control) => { const selected = control === button; control.classList.toggle('is-selected', selected); control.setAttribute('aria-pressed', String(selected)); }); if (panel) panel.textContent = placement; void floating.updatePosition(); }); }); });</script><script setup lang="ts">import { offset, useFloating, vFloating, type Placement,} from '@floating-ui-plus/vue';import {shallowRef} from 'vue';import {DEFAULT_PLACEMENT, PLACEMENT_OPTIONS} from '../../example-data';
const selectedPlacement = shallowRef<Placement>(DEFAULT_PLACEMENT);const reference = shallowRef<HTMLElement | null>(null);const floating = shallowRef<HTMLElement | null>(null);const positioning = useFloating(reference, floating, { placement: selectedPlacement, middleware: [offset(18)],});</script>
<template> <div class="vue-placement-stage" aria-label="Interactive placement selector"> <button v-for="placement in PLACEMENT_OPTIONS" :key="placement" type="button" class="vue-placement-control" :class="{ 'is-selected': placement === selectedPlacement }" :value="placement" :aria-pressed="placement === selectedPlacement" :aria-label="`Place floating element at ${placement}`" @click="selectedPlacement = placement" > <span aria-hidden="true"></span> </button>
<div ref="reference" class="vue-placement-reference">Reference</div> <div ref="floating" v-floating="positioning" class="vue-placement-floating" :data-placement="positioning.placement.value" role="status" > {{ positioning.placement.value }} </div> </div></template>The placement card exposes all 12 values (top, top-start, top-end, and
the corresponding bottom/right/left variants). Clicking a control updates the
root and calls updatePosition():
const placement = button.dataset.placementControl as Placement;floating.placement = placement;await floating.updatePosition();offset(18) makes the gap visible. Use the generated PLACEMENT and
PLACEMENTS exports for typed constants, or pass ordinary placement strings.
The Vue version binds placement through FloatingRoot options or the
composable state.