Middleware
flip
Switches to alternative placements when the current side is blocked.
flip switches to alternative placements when the preferred placement does not fit in the viewport. Use it to start from a preferred side (such as "bottom") and only move elsewhere if that side overflows.
Type
function flip(options?: FlipOptions): Middleware;
interface FlipOptions {
mainAxis?: boolean;
crossAxis?: boolean | "alignment";
fallbackAxisSideDirection?: "none" | "start" | "end";
flipAlignment?: boolean;
fallbackPlacements?: Array<Placement>;
fallbackStrategy?: "bestFit" | "initialPlacement";
padding?: Padding;
boundary?: Boundary;
rootBoundary?: RootBoundary;
elementContext?: ElementContext;
altBoundary?: boolean;
}
Options
| Name | Type | Default | Notes |
|---|---|---|---|
mainAxis | boolean | true | Allows flipping to the opposite side along the main axis (e.g. "bottom" → "top"). |
crossAxis | boolean | "alignment" | true | Allows flipping along the cross axis when both main axis sides overflow. |
fallbackAxisSideDirection | "none" | "start" | "end" | "none" | Which side to try when flipping along the cross axis. |
flipAlignment | boolean | true | Flips alignment (e.g. "bottom-start" → "bottom-end") when side alignment overflows. |
fallbackPlacements | Array<Placement> | Opposite side | Explicit ordered list of placements to try before giving up. |
fallbackStrategy | "bestFit" | "initialPlacement" | "bestFit" | Strategy when all placements overflow: pick the best fit, or reset to preferred. |
padding | Padding | 0 | Minimum clearance from the clipping boundary. |
boundary | Boundary | "clippingAncestors" | Clipping boundary element or rect. |
Returns
flip returns a Middleware object with name: "flip". It populates middlewareData.value.flip with internal overflow metrics.
Details
Pipeline Placement
flip runs after offset and before shift:
offset: Adds required spacing.flip: Checks if the panel + offset fits on the preferred side. If not, flips to an alternative placement.shift: Once the best placement side is determined, shifts the panel along the edge to prevent clipping.
If shift runs before flip, shifting might slide the panel into an awkward corner and prevent flip from triggering properly.
Mutually Exclusive with autoPlacement
flip and autoPlacement solve opposite goals:
- Use
flipwhen you have a preferred placement and only want to move if it overflows. - Use
autoPlacementwhen you have no preference and want the system to choose whichever side has the most space. - Do not enable both simultaneously.
Example
<script setup lang="ts">
import { ref } from "vue";
import { useFloatingNode, usePosition } from "v-float";
const anchorEl = ref<HTMLElement | null>(null);
const floatingEl = ref<HTMLElement | null>(null);
const node = useFloatingNode({ anchorEl, floatingEl });
const { placement } = usePosition(node, {
placement: "bottom-start",
middlewares: {
offset: 8,
flip: {
fallbackPlacements: ["top-start", "right-start", "left-start"],
padding: 8,
},
shift: { padding: 8 },
},
});
</script>
<template>
<button ref="anchorEl">Anchor</button>
<div v-if="node.open" ref="floatingEl" :data-placement="placement">Flipping floating panel</div>
</template>
See Also
autoPlacement- Alternative that automatically picks the largest sideshift- Nudges the floating element to keep it inside the boundaryoffset- Adds spacing before flip checks run- Middleware Ordering Gotchas - Detailed ordering rules