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

NameTypeDefaultNotes
mainAxisbooleantrueAllows flipping to the opposite side along the main axis (e.g. "bottom" → "top").
crossAxisboolean | "alignment"trueAllows 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.
flipAlignmentbooleantrueFlips alignment (e.g. "bottom-start" → "bottom-end") when side alignment overflows.
fallbackPlacementsArray<Placement>Opposite sideExplicit 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.
paddingPadding0Minimum clearance from the clipping boundary.
boundaryBoundary"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:

  1. offset: Adds required spacing.
  2. flip: Checks if the panel + offset fits on the preferred side. If not, flips to an alternative placement.
  3. 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 flip when you have a preferred placement and only want to move if it overflows.
  • Use autoPlacement when 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

Released under the MIT License. Copyright © 2026