useFocus
useFocus opens and closes a floating node when the anchor gains or loses focus. By default, it activates only for keyboard focus (:focus-visible), preventing unwanted tooltips when clicking with a mouse.
Type
function useFocus(node: FloatingNode, options?: UseFocusOptions): UseFocusReturn;
interface UseFocusOptions {
enabled?: MaybeRefOrGetter<boolean>;
requireFocusVisible?: MaybeRefOrGetter<boolean>;
ignoreFocusOut?: (target: EventTarget | null) => boolean;
}
interface UseFocusReturn {
cleanup: () => void;
}
Options
| Name | Type | Default | Notes |
|---|---|---|---|
enabled | MaybeRefOrGetter<boolean> | true | Reactive toggle. Disabling removes all focus listeners. |
requireFocusVisible | MaybeRefOrGetter<boolean> | true | When true, opens only for keyboard navigation, ignoring pointer clicks. |
ignoreFocusOut | (target: EventTarget | null) => boolean | undefined | Predicate to prevent closing when focus transitions to selected elements. |
Returns
| Name | Type | Notes |
|---|---|---|
cleanup | () => void | Manually unregisters all focus listeners. Also executes on component unmount. |
Details
Focus Visible Heuristic
Most browsers set focus on a button when clicked with a mouse or tapped on mobile. If focus listeners opened a tooltip unconditionally, clicking a button would leave a sticky tooltip floating on screen.
With requireFocusVisible: true (the default), useFocus inspects the browser's :focus-visible pseudo-class. Tabbing into a button opens the tooltip; clicking the button does not.
Deferred Blur and Family Awareness
When focus leaves the anchor, dismissal is deferred to the next tick to verify where focus landed:
- If focus moved into the floating panel, the surface remains open.
- If focus moved into a child submenu or descendant overlay,
node.contains(activeEl)keeps the parent surface open. - Switching tabs in the browser and returning will not reopen a closed surface.
Accessibility Pairing
Combine useFocus with useHover and useRole(node, { role: "tooltip" }) to fulfill WCAG Success Criterion 1.4.13 (Content on Hover or Focus).
Example
<script setup lang="ts">
import { ref } from "vue";
import { useFloatingNode, useFocus, useHover, usePosition, useRole } from "v-float";
const anchorEl = ref<HTMLElement | null>(null);
const floatingEl = ref<HTMLElement | null>(null);
const node = useFloatingNode({ anchorEl, floatingEl });
usePosition(node, {
placement: "top",
middlewares: {
offset: 6,
flip: true,
shift: { padding: 8 },
},
});
useHover(node);
useFocus(node);
useRole(node, { role: "tooltip" });
</script>
<template>
<button ref="anchorEl">Tab to focus me</button>
<div v-if="node.open.value" ref="floatingEl" role="tooltip">Helpful keyboard-accessible hint</div>
</template>
See Also
useHover- Pointer hover triggeruseRole- ARIA role andaria-describedbysynchronizationuseEscapeKey- Dismissal on Escape key- Build Accessible Tooltips - Complete tooltip pattern guide