or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

docs

index.md
tile.json

tessl/npm-floating-ui--vue

Vue.js integration for Floating UI positioning library that provides composables and utilities for creating floating elements like tooltips, popovers, and dropdowns with automatic positioning and collision detection.

Workspace
tessl
Visibility
Public
Created
Last updated
Describes
npmpkg:npm/@floating-ui/vue@1.1.x

To install, run

npx @tessl/cli install tessl/npm-floating-ui--vue@1.1.0

index.mddocs/

@floating-ui/vue

@floating-ui/vue provides Vue.js integration for Floating UI, a positioning library for creating floating elements like tooltips, popovers, dropdowns, and menus. It offers Vue-specific composables and utilities built on top of @floating-ui/dom, enabling developers to easily create accessible floating UI components in Vue applications with automatic positioning, collision detection, and Vue-reactive state management.

Package Information

  • Package Name: @floating-ui/vue
  • Package Type: npm
  • Language: TypeScript
  • Installation: npm install @floating-ui/vue

Core Imports

import { useFloating, arrow } from "@floating-ui/vue";

You can also import middleware directly:

import { useFloating, arrow, offset, flip, shift } from "@floating-ui/vue";

For CommonJS:

const { useFloating, arrow, offset, flip, shift } = require("@floating-ui/vue");

Basic Usage

<template>
  <div>
    <button ref="referenceRef" @click="show = !show">
      Toggle tooltip
    </button>
    <div
      v-if="show"
      ref="floatingRef"
      :style="floatingStyles"
      class="tooltip"
    >
      This is a tooltip
      <div ref="arrowRef" :style="arrowStyles" class="arrow"></div>
    </div>
  </div>
</template>

<script setup>
import { ref, computed } from 'vue';
import { useFloating, arrow, offset, flip, shift } from '@floating-ui/vue';

const show = ref(false);
const referenceRef = ref(null);
const floatingRef = ref(null);
const arrowRef = ref(null);

const { floatingStyles, placement, middlewareData } = useFloating(
  referenceRef,
  floatingRef,
  {
    open: show,
    placement: 'top',
    middleware: [
      offset(10),
      flip(),
      shift({ padding: 5 }),
      arrow({
        element: arrowRef,
        padding: 5,
      }),
    ],
  }
);

const arrowStyles = computed(() => {
  if (!middlewareData.value.arrow) return {};
  
  const { x, y } = middlewareData.value.arrow;
  return {
    left: x != null ? `${x}px` : '',
    top: y != null ? `${y}px` : '',
  };
});
</script>

Architecture

@floating-ui/vue is built around several key architectural components that work together to provide Vue-reactive floating element positioning:

  • Vue Composable Layer: The useFloating composable serves as the primary interface, providing Vue-reactive state management for positioning data and automatic cleanup through Vue's lifecycle system.
  • Template Ref Integration: Seamlessly integrates with Vue's template ref system, accepting both element refs and component instance refs while handling the unwrapping automatically.
  • Reactive Configuration: All configuration options (placement, middleware, open state) accept Vue refs, getters, or static values, enabling fully reactive positioning updates when dependencies change.
  • Middleware Pipeline: Leverages @floating-ui/dom's middleware system for extensible positioning modifications, with Vue-specific wrappers (like the arrow function) that handle Vue ref unwrapping.
  • Automatic Updates: Provides intelligent position updates through watchers that respond to configuration changes and element mounting/unmounting, with optional manual update control.
  • Type Safety: Full TypeScript integration with Vue-specific type wrappers (MaybeReadonlyRef, MaybeReadonlyRefOrGetter) that preserve type safety while accommodating Vue's reactivity patterns.

Capabilities

useFloating Composable

Main composable for positioning floating elements relative to reference elements with Vue reactivity.

/**
 * Computes the x and y coordinates that will place the floating element next to a reference element
 * @param reference - The reference template ref
 * @param floating - The floating template ref  
 * @param options - The floating options
 * @returns Object with reactive positioning values and utilities
 */
function useFloating<T extends ReferenceElement = ReferenceElement>(
  reference: Readonly<Ref<MaybeElement<T>>>,
  floating: Readonly<Ref<MaybeElement<FloatingElement>>>,
  options?: UseFloatingOptions<T>
): UseFloatingReturn;

interface UseFloatingOptions<T extends ReferenceElement = ReferenceElement> {
  /** Represents the open/close state of the floating element. @default true */
  open?: MaybeReadonlyRefOrGetter<boolean | undefined>;
  /** Where to place the floating element relative to its reference element. @default 'bottom' */
  placement?: MaybeReadonlyRefOrGetter<Placement | undefined>;
  /** The type of CSS position property to use. @default 'absolute' */
  strategy?: MaybeReadonlyRefOrGetter<Strategy | undefined>;
  /** These are plain objects that modify the positioning coordinates in some fashion, or provide useful data for the consumer to use. @default undefined */
  middleware?: MaybeReadonlyRefOrGetter<Middleware[] | undefined>;
  /** Whether to use transform instead of top and left styles to position the floating element (floatingStyles). @default true */
  transform?: MaybeReadonlyRefOrGetter<boolean | undefined>;
  /** Callback to handle mounting/unmounting of the elements. @default undefined */
  whileElementsMounted?: (
    reference: T,
    floating: FloatingElement,
    update: () => void,
  ) => () => void;
}

interface UseFloatingReturn {
  /** The x-coord of the floating element */
  x: Readonly<Ref<number>>;
  /** The y-coord of the floating element */
  y: Readonly<Ref<number>>;
  /** The stateful placement, which can be different from the initial placement passed as options */
  placement: Readonly<Ref<Placement>>;
  /** The type of CSS position property to use */
  strategy: Readonly<Ref<Strategy>>;
  /** Additional data from middleware */
  middlewareData: Readonly<Ref<MiddlewareData>>;
  /** The boolean that let you know if the floating element has been positioned */
  isPositioned: Readonly<Ref<boolean>>;
  /** CSS styles to apply to the floating element to position it */
  floatingStyles: Readonly<Ref<{
    position: Strategy;
    top: string;
    left: string;
    transform?: string;
    willChange?: string;
  }>>;
  /** The function to update floating position manually */
  update: () => void;
}

Arrow Middleware

Positions an arrow element centered relative to the reference element.

/**
 * Positions an inner element of the floating element such that it is centered to the reference element
 * @param options - The arrow options
 * @returns Middleware for arrow positioning
 */
function arrow(options: ArrowOptions): Middleware;

interface ArrowOptions {
  /** The arrow element or template ref to be positioned. @required */
  element: MaybeReadonlyRefOrGetter<MaybeElement<Element>>;
  /** The padding between the arrow element and the floating element edges. Useful when the floating element has rounded corners. @default 0 */
  padding?: Padding;
}

Re-exported Middleware from @floating-ui/dom

The following middleware functions are re-exported from @floating-ui/dom for convenience:

/** Chooses the placement that has the most space available automatically */
function autoPlacement(options?: AutoPlacementOptions): Middleware;

/** Changes the placement of the floating element in order to keep it in view when the preferred placement does not fit */
function flip(options?: FlipOptions): Middleware;

/** Shifts the floating element in order to keep it in view when it will overflow the clipping boundary */
function shift(options?: ShiftOptions): Middleware;

/** Provides data to position an inner element of the floating element so that it appears centered to the reference element */
function offset(options?: OffsetOptions): Middleware;

/** Provides data that allows you to change the size of the floating element */
function size(options?: SizeOptions): Middleware;

/** Provides data to hide the floating element in applicable situations */
function hide(options?: HideOptions): Middleware;

/** Provides improved positioning for inline reference elements that can span over multiple lines */
function inline(options?: InlineOptions): Middleware;

/** Built-in limitShift() limiter that will stop shift() at a certain point */
function limitShift(options?: {
  /** Offset when limiting starts. @default 0 */
  offset?: number | OffsetOptions;
  /** Axis that is limited. @default 'all' */
  mainAxis?: boolean;
  /** Cross axis that is limited. @default 'all' */
  crossAxis?: boolean;
}): {
  fn: (state: MiddlewareState) => Coords;
};

Utility Functions

/** Computes the `x` and `y` coordinates that will place the floating element next to a reference element */
function computePosition(
  reference: ReferenceElement,
  floating: FloatingElement,
  options?: ComputePositionConfig
): Promise<ComputePositionReturn>;

/** Automatically updates the position of the floating element when necessary */
function autoUpdate(
  reference: ReferenceElement,
  floating: FloatingElement,
  update: () => void,
  options?: AutoUpdateOptions
): () => void;

/** Resolves with an object of overflow side offsets that determine how much the element is overflowing a given clipping boundary */
function detectOverflow(
  state: MiddlewareState,
  options?: DetectOverflowOptions
): Promise<SideObject>;

/** Returns the overflow ancestors that can potentially clip the floating element */
function getOverflowAncestors(
  element: Element,
  list?: (Element | Window)[]
): (Element | Window)[];

/** This is useful for packages that create a \"platform\" */
const platform: Platform;

Types

Core Vue-specific Types

/** Represents a value that can be a readonly ref */
type MaybeReadonlyRef<T> = T | Readonly<Ref<T>>;

/** Represents a value, readonly ref, or getter function */
type MaybeReadonlyRefOrGetter<T> = MaybeReadonlyRef<T> | (() => T);

/** Represents a DOM element, Vue component instance, or nullish value */
type MaybeElement<T> = T | ComponentPublicInstance | null | undefined;

Re-exported Types from @floating-ui/dom

The package re-exports all types from @floating-ui/dom including:

/** Placement options for positioning */
type Placement = 
  | 'top'
  | 'top-start'
  | 'top-end'
  | 'right'
  | 'right-start'
  | 'right-end'
  | 'bottom'
  | 'bottom-start'
  | 'bottom-end'
  | 'left'
  | 'left-start'
  | 'left-end';

/** CSS positioning strategy */
type Strategy = 'absolute' | 'fixed';

/** Reference element types */
type ReferenceElement = Element | VirtualElement;

/** Floating element type */
type FloatingElement = HTMLElement;

/** Virtual reference element for custom positioning */
interface VirtualElement {
  getBoundingClientRect(): ClientRectObject;
  contextElement?: Element;
}

/** Middleware function for positioning modifications */
interface Middleware {
  name: string;
  options?: any;
  fn: (state: MiddlewareState) => Promise<MiddlewareReturn> | MiddlewareReturn;
}

/** Data returned by middleware */
interface MiddlewareData {
  [key: string]: any;
}

/** Padding configuration for middleware */
type Padding = number | Partial<{
  top: number;
  right: number;
  bottom: number;
  left: number;
}>;

/** Coordinates interface */
interface Coords {
  x: number;
  y: number;
}

/** Rectangle dimensions */
interface Rect extends Coords {
  width: number;
  height: number;
}

/** Client rectangle object */
interface ClientRectObject extends Rect {
  top: number;
  left: number;
  right: number;
  bottom: number;
}

Usage Examples

Basic Tooltip

<template>
  <div>
    <button ref="reference" @click="open = !open">
      Click me
    </button>
    <div
      v-if="open"
      ref="floating"
      :style="floatingStyles"
      class="tooltip"
    >
      Tooltip content
    </div>
  </div>
</template>

<script setup>
import { ref } from 'vue';
import { useFloating, offset } from '@floating-ui/vue';

const open = ref(false);
const reference = ref(null);
const floating = ref(null);

const { floatingStyles } = useFloating(reference, floating, {
  open,
  placement: 'top',
  middleware: [offset(10)],
});
</script>

Dropdown with Auto-placement

<template>
  <div>
    <button ref="reference" @click="open = !open">
      Menu
    </button>
    <div
      v-if="open"
      ref="floating"
      :style="floatingStyles"
      class="dropdown"
    >
      <div>Item 1</div>
      <div>Item 2</div>
      <div>Item 3</div>
    </div>
  </div>
</template>

<script setup>
import { ref } from 'vue';
import { useFloating, autoPlacement, offset } from '@floating-ui/vue';

const open = ref(false);
const reference = ref(null);
const floating = ref(null);

const { floatingStyles } = useFloating(reference, floating, {
  open,
  middleware: [
    offset(5),
    autoPlacement(),
  ],
});
</script>

Using with Component References

<template>
  <div>
    <MyButton ref="reference" @click="open = !open">
      Click me
    </MyButton>
    <MyTooltip
      v-if="open"
      ref="floating"
      :style="floatingStyles"
    >
      Tooltip content
    </MyTooltip>
  </div>
</template>

<script setup>
import { ref } from 'vue';
import { useFloating, offset } from '@floating-ui/vue';

const open = ref(false);
const reference = ref(null);
const floating = ref(null);

const { floatingStyles } = useFloating(reference, floating, {
  open,
  placement: 'bottom',
  middleware: [offset(10)],
});
</script>

Virtual Reference Element

<template>
  <div @contextmenu="showContextMenu">
    Right-click anywhere
    <div
      v-if="open"
      ref="floating"
      :style="floatingStyles"
      class="context-menu"
    >
      <div>Cut</div>
      <div>Copy</div>
      <div>Paste</div>
    </div>
  </div>
</template>

<script setup>
import { ref } from 'vue';
import { useFloating } from '@floating-ui/vue';

const open = ref(false);
const reference = ref(null);
const floating = ref(null);

const { floatingStyles } = useFloating(reference, floating, {
  open,
  placement: 'right-start',
});

function showContextMenu(event) {
  event.preventDefault();
  
  // Create virtual reference element at cursor position
  reference.value = {
    getBoundingClientRect() {
      return {
        x: event.clientX,
        y: event.clientY,
        top: event.clientY,
        left: event.clientX,
        right: event.clientX,
        bottom: event.clientY,
        width: 0,
        height: 0,
      };
    },
  };
  
  open.value = true;
}
</script>