Core Concepts

Interaction Model

Learn how VFloat opens, closes, and coordinates floating surfaces.

VFloat's interaction composables look separate on the surface, but they are meant to work together through one shared state model.

That shared model is the difference between a pile of event helpers and a composable floating system.

The core idea

Interaction composables do not usually position anything themselves. They answer a different question:

"When should this floating surface open or close?"

Examples:

useOutsideClick and useEscapeKey are decoupled primitives. Mix and match them based on the exact UX requirements of your surface (e.g. tooltips typically only need useEscapeKey, whereas modals and dropdowns usually use both).

One node, many behaviors

A floating surface often needs more than one interaction rule at once.

For example, an accessible tooltip may need hover for pointer users and focus for keyboard users. A popover may need click to open, outside click to close, and Escape to close.

Those are not competing systems if they all share one node. They are just different inputs acting on the same open state.

A typical combination

This example shows a common click-driven combination:

<script setup lang="ts">
import { ref } from "vue";
import { useClick, useEscapeKey, useFloatingNode, useOutsideClick } from "v-float";

const anchorEl = ref<HTMLElement | null>(null);
const floatingEl = ref<HTMLElement | null>(null);

const node = useFloatingNode({ anchorEl, floatingEl });

useClick(node);
useOutsideClick(node);
useEscapeKey(node);
</script>

useOutsideClick(node) closes when the user interacts outside the surface (with built-in family awareness so clicking inside child submenus won't dismiss the parent). useEscapeKey(node) dismisses on Escape, respecting IME composition and nested tree hierarchy.

Where to go next

Released under the MIT License. Copyright © 2026