Skip to main content
Vuetify0 is now in beta!
Vuetify0 Logo
Theme
Mode
Palettes
Accessibility
Vuetify One
Sign in to Vuetify One

Access premium tools across the Vuetify ecosystem — Bin, Play, Studio, and more.

Not a subscriber? See what's included

usePresence

Animation-agnostic mount lifecycle management.

Usage

The usePresence composable implements a state machine that controls when content should be in the DOM. It handles lazy mounting, enter/exit timing, and cleanup — without opinion on how animation happens.

ts
import { usePresence } from '@vuetify/v0'
import { shallowRef } from 'vue'

const isOpen = shallowRef(false)

const { isMounted, isPresent, isLeaving, state, done } = usePresence({
  present: isOpen,
  lazy: true,
  immediate: false,
})

// isMounted — controls v-if (true during mounted, present, and leaving)
// state — 'unmounted' | 'mounted' | 'present' | 'leaving'
// done() — call when exit animation finishes

Architecture

usePresence State Machine

Use controls to zoom and pan. Click outside or press Escape to close.

usePresence State Machine

Options

OptionTypeDefaultNotes
presentMaybeRefOrGetter<boolean>Required. Drives visibility — when truthy, content enters; when falsy, begins leaving
lazybooleanfalseDelay first mount until present is true for the first time
immediatebooleantrueAuto-resolve the leaving state on the next tick if done() is not called. Set to false for JS-driven animations that need full timing control

Reactivity

PropertyTypeDescription
stateRef<PresenceState>Current lifecycle state
isMountedRef<boolean>Whether content should be in the DOM
isPresentRef<boolean>Whether content is logically active
isLeavingRef<boolean>Whether an exit is in progress
done() => voidSignal that exit animation is complete

Examples

Animated Accordion

A single-open FAQ accordion where every panel drives its own usePresence instance, so each region is fully absent from the DOM when collapsed and animates in and out with CSS keyframes. The composable owns only the demo state — the panel list and which id is active — while the reusable panel component owns the mount lifecycle. Opening one panel collapses the previous one, which means two presence machines run at once: one entering, one leaving. This is the case a plain v-show cannot handle, because the leaving panel must stay mounted long enough to finish its exit animation before it is removed.

The pattern hinges on immediate: false together with done(). With the default immediate: true, usePresence auto-resolves the leaving state on the next microtask — fine for content with no exit animation, but it races a CSS animation. Setting immediate: false hands timing control to the panel: isMounted gates the v-if, state is reflected onto a data-state attribute that selects the enter or leave keyframe, and done() is called from animationend only while isLeaving is true (so the enter animation’s own animationend is ignored). Until done() runs, the element stays mounted and the exit animation completes cleanly.

Reach for this when each item needs an independent enter/exit animation before it leaves the DOM. If you only need deferred first mount with no exit delay, pass lazy: true and leave immediate at its default. For the compound component that wraps this composable with slot-based transitions, see Presence; for the simpler defer-until-first-open case, see useLazy.

FileRole
useAccordion.tsOwns the panel data and the active-id state with a toggle
AccordionPanel.vueDrives one usePresence instance and resolves the CSS exit via done()
accordion.vueWires the composable to the panels and renders the headers
Orders placed before 2pm ship the same business day. Tracking is emailed once the carrier scans the parcel.

presence state: mounted

FAQ

Discord
Need help? Join our community for support and discussions ↗

API Reference

The following API details are for the usePresence composable.
Was this page helpful?

Ctrl+/