Skip to content

shift

A visibility optimizer that shifts the floating element along the specified axes in order to keep it in view.

Scroll horizontally

This is useful for preventing overflow while maintaining the desired placement as best as possible.

Usage

import {computePosition, shift} from '@floating-ui/dom';
 
computePosition(referenceEl, floatingEl, {
  middleware: [shift()],
});
import {computePosition, shift} from '@floating-ui/dom';
 
computePosition(referenceEl, floatingEl, {
  middleware: [shift()],
});

Options

These are the options you can pass to shift()shift().

interface Options extends DetectOverflowOptions {
  mainAxis?: boolean;
  crossAxis?: boolean;
  limiter?: {
    fn: (state: MiddlewareState) => Coords;
    options?: any;
  };
}
interface Options extends DetectOverflowOptions {
  mainAxis?: boolean;
  crossAxis?: boolean;
  limiter?: {
    fn: (state: MiddlewareState) => Coords;
    options?: any;
  };
}

mainAxis

default: truetrue

This is the main axis in which shifting is applied.

  • x-axis for 'top''top' and 'bottom''bottom' placements
  • y-axis for 'left''left' and 'right''right' placements
shift({
  mainAxis: false,
});
shift({
  mainAxis: false,
});
Scroll horizontally

crossAxis

default: falsefalse

This is the cross axis in which shifting is applied, the opposite axis of mainAxismainAxis.

Enabling this can lead to the floating element overlapping the reference element, which may not be desired and is often replaced by the flip()flip() middleware.

shift({
  crossAxis: true,
});
shift({
  crossAxis: true,
});
Scroll down

limiter

default: no-op

This accepts a function that limits the shifting done, in order to prevent detachment or “overly-eager” behavior. The behavior is to stop shifting once the opposite edges of the elements are aligned.

import {shift, limitShift} from '@floating-ui/dom';
 
shift({
  limiter: limitShift(),
});
import {shift, limitShift} from '@floating-ui/dom';
 
shift({
  limiter: limitShift(),
});

This function itself takes options.

limitShift.mainAxis

default: truetrue

Whether to apply limiting on the main axis.

shift({
  limiter: limitShift({
    mainAxis: false,
  }),
});
shift({
  limiter: limitShift({
    mainAxis: false,
  }),
});

limitShift.crossAxis

default: truetrue

Whether to apply limiting on the cross axis.

shift({
  limiter: limitShift({
    crossAxis: false,
  }),
});
shift({
  limiter: limitShift({
    crossAxis: false,
  }),
});

limitShift.offset

default: 00

This will offset when the limiting starts. A positive number will start limiting earlier, while negative later.

shift({
  limiter: limitShift({
    // Start limiting 5px earlier
    offset: 5,
  }),
});
shift({
  limiter: limitShift({
    // Start limiting 5px earlier
    offset: 5,
  }),
});

This can also take a function, which provides the RectRects of each element to read their dimensions:

shift({
  limiter: limitShift({
    // Start limiting by the reference's width earlier
    offset: ({rects, placement}) => rects.reference.width,
  }),
});
shift({
  limiter: limitShift({
    // Start limiting by the reference's width earlier
    offset: ({rects, placement}) => rects.reference.width,
  }),
});

You may also pass an object to configure both axes:

shift({
  limiter: limitShift({
    // object
    offset: {
      mainAxis: 10,
      crossAxis: 5,
    },
    // or a function which returns one
    offset: ({rects, placement}) => ({
      mainAxis: rects.reference.height,
      crossAxis: rects.floating.width,
    }),
  }),
});
shift({
  limiter: limitShift({
    // object
    offset: {
      mainAxis: 10,
      crossAxis: 5,
    },
    // or a function which returns one
    offset: ({rects, placement}) => ({
      mainAxis: rects.reference.height,
      crossAxis: rects.floating.width,
    }),
  }),
});

…detectOverflowOptions

All of detectOverflow’s options can be passed. For instance:

shift({
  padding: 5, // 0 by default
});
shift({
  padding: 5, // 0 by default
});

If you find the padding does not get applied on the right side, see Handling large content.

Deriving options from state

You can derive the options from the middleware lifecycle state:

shift((state) => ({
  padding: state.rects.reference.width,
}));
shift((state) => ({
  padding: state.rects.reference.width,
}));

Data

The following data is available in middlewareData.shiftmiddlewareData.shift:

interface Data {
  x: number;
  y: number;
}
interface Data {
  x: number;
  y: number;
}

xx and yy represent how much the floating element has been shifted along that axis. The values are offsets, and therefore can be negative.