v-float
v0.11.0
Published
Vue 3 port of Floating UI - a library for positioning floating elements
Readme
V-Float
Work in progress: This library is under active development. APIs may change without notice and breaking changes can land without deprecation windows or warnings. Not recommended for production use yet.
A Vue 3 library for positioning floating UI elements like tooltips, popovers, dropdowns, and modals. Built on top of @floating-ui/dom with Vue 3 Composition API.
Features
- Precise Positioning: Pixel-perfect positioning with automatic collision detection
- Vue 3 Composables: Reactive composables designed for the Composition API
- Interaction Handling: Built-in hover, focus, click, and dismiss behaviors
- Arrow Positioning:
useArrowcomposable for positioning arrow elements - Lightweight: Tree-shakable with minimal bundle impact
- Cross-platform: Works on desktop, mobile, and touch devices
- TypeScript: Full TypeScript support with comprehensive type definitions
Installation
# With pnpm (recommended)
pnpm add v-float
# With npm
npm install v-float
# With yarn
yarn add v-floatQuick Start
Basic Tooltip
<script setup lang="ts">
import { useTemplateRef } from "vue";
import { useFloating, useHover, offset } from "v-float";
const anchorEl = useTemplateRef("anchorEl");
const floatingEl = useTemplateRef("floatingEl");
const context = useFloating(anchorEl, floatingEl, {
placement: "top",
middlewares: [offset(8)],
});
useHover(context);
</script>
<template>
<button ref="anchorEl">Hover me</button>
<div v-if="context.state.open.value" ref="floatingEl" :style="context.position.styles.value">
This is a tooltip
</div>
</template>Dropdown Menu
<script setup lang="ts">
import { useTemplateRef } from "vue";
import { useFloating, useClick, useEscapeKey, offset, flip, shift } from "v-float";
const triggerEl = useTemplateRef("triggerEl");
const menuEl = useTemplateRef("menuEl");
const context = useFloating(triggerEl, menuEl, {
placement: "bottom-start",
middlewares: [offset(4), flip(), shift({ padding: 8 })],
});
useClick(context);
useEscapeKey(context, {
onEscape: () => context.setOpen(false),
});
</script>
<template>
<button ref="triggerEl">Open Menu</button>
<div v-if="context.state.open.value" ref="menuEl" :style="context.position.styles.value">
<div>Menu Item 1</div>
<div>Menu Item 2</div>
<div>Menu Item 3</div>
</div>
</template>Tooltip with Arrow
<script setup lang="ts">
import { useTemplateRef } from "vue";
import { useFloating, useHover, useArrow, offset, flip } from "v-float";
const anchorEl = useTemplateRef("anchorEl");
const tooltipEl = useTemplateRef("tooltipEl");
const arrowEl = useTemplateRef("arrowEl");
const context = useFloating(anchorEl, tooltipEl, {
placement: "top",
middlewares: [offset(8), flip()],
});
useHover(context);
const { arrowStyles } = useArrow(context, {
element: arrowEl,
offset: "-4px",
});
</script>
<template>
<button ref="anchorEl">Hover me</button>
<div
v-if="context.state.open.value"
ref="tooltipEl"
:style="context.position.styles.value"
class="tooltip"
>
This is a tooltip with an arrow
<div ref="arrowEl" class="arrow" :style="arrowStyles"></div>
</div>
</template>
<style scoped>
.tooltip {
background: white;
border: 1px solid #ddd;
border-radius: 4px;
padding: 8px 12px;
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
}
.arrow {
position: absolute;
width: 8px;
height: 8px;
background: white;
border: 1px solid #ddd;
transform: rotate(45deg);
z-index: -1;
}
</style>Core Composables
Positioning
**useFloating**: Core positioning logic with middleware support**useArrow**: Position arrow elements pointing to the anchor
Interactions
**useHover**: Hover interactions with configurable delays**useFocus**: Focus/blur event handling for keyboard navigation**useClick**: Click event handling with toggle and dismiss options**useEscapeKey**: Close on ESC key press with composition handling**useClientPoint**: Position floating elements at cursor/touch coordinates
Middleware
All Floating UI middleware are supported:
**offset**: Add distance between anchor and floating element**flip**: Flip placement when there's insufficient space**shift**: Shift floating element to stay in view**hide**: Hide floating element when anchor is not visible**autoPlacement**: Automatically choose the best placement**size**: Resize floating element to fit within viewport
Arrow positioning is handled by the [useArrow](/api/use-arrow) composable, which owns arrow registration for the floating context.
Project Status
- WIP and evolving rapidly; expect breaking changes without deprecations.
- API, docs, and examples are subject to change and may be incomplete.
- Feedback and contributions are welcome while the API stabilizes.
TypeScript Support
V-Float is built with TypeScript and provides comprehensive type definitions:
Browser Support
- Modern browsers: Chrome, Firefox, Safari, Edge
- Mobile browsers: iOS Safari, Chrome Mobile
- Node.js: SSR compatible (with proper hydration)
Documentation
For complete documentation with interactive examples, visit the V-Float Documentation.
Contributing
Contributions are welcome! Please read our contributing guidelines and submit pull requests to our GitHub repository.
Credits
V-Float is built on top of the excellent work of:
- Floating UI - For the core positioning and collision detection algorithms
- VueUse - For Vue composition utilities and best practices
License
MIT License - see LICENSE file for details.
