Skip to main content
Vuetify0 is now a release candidate!
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

useLazy

A composable for deferring content rendering until first activation, with optional reset on deactivation.

Usage

The useLazy composable tracks whether content has been activated at least once. Content renders only after first activation (unless eager mode is enabled), reducing initial render cost for components like dialogs, menus, and tooltips.

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

const isOpen = shallowRef(false)

const { isBooted, hasContent, onAfterLeave } = useLazy(isOpen)

// hasContent becomes true after isOpen is first set to true
// onAfterLeave resets lazy state for transition integration

Architecture

useLazy Lifecycle

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

useLazy Lifecycle

Reactivity

Property/MethodReactiveNotes
isBootedShallowRef, readonly
hasContentComputed from isBooted || eager || active
activeAccepts MaybeRefOrGetter, watched for changes
eagerAccepts MaybeRefOrGetter in options

Examples

Lazy Tab Panels

A three-tab interface where each panel’s heavy content mounts only the first time its tab is opened, and a live mount counter proves each panel mounts exactly once no matter how often you switch back and forth.

Each panel is a LazyTab that calls useLazy(() => active) and gates its body on hasContent. The gate starts false, so the expensive HeavyPanel subtree is never created for a tab the reader has not visited yet. The moment a tab is first selected, isBooted flips to true and hasContent stays true permanently — this example deliberately omits onAfterLeave, so once a panel boots it survives every subsequent tab switch. The panel wrapper toggles visibility with v-show, keeping the already-mounted DOM around for instant re-display instead of paying the mount cost again. HeavyPanel increments a shared counter in its onMounted hook, and the readout under the tabs confirms the count never climbs past one per panel.

This is the canonical pattern for tabbed dashboards, wizard steps, and any layout where most panels are never viewed in a given session. Contrast it with usePresence, which orchestrates enter and leave animations rather than deferring the first mount, and with useToggleScope for tearing an effect scope down when content hides. To reclaim memory when a panel closes, wire onAfterLeave into a Transition so isBooted resets and the subtree unmounts — at the cost of re-mounting on the next open.

FileRole
tabs.tsTab definitions plus a shared composable that tracks per-panel mount counts
HeavyPanel.vueThe expensive content; reports its mount to the shared counter
LazyTab.vueWraps a panel with useLazy, gating its body on hasContent
demo.vueRenders the tab bar, the lazy panels, and the live mount readout

Overview row 1

Overview row 2

Overview row 3

Overview row 4

Overview row 5

Overview row 6

isBooted: true · hasContent: true

Panel mounts

Overview: 0 mount(s)

Analytics: 0 mount(s)

Settings: 0 mount(s)

Switch tabs and back — each panel mounts once, then stays.

Recipes

Delay

Use the delay option to defer the first mount by a fixed number of milliseconds. This prevents a flash of content for operations that complete very quickly:

ts
const { hasContent } = useLazy(isOpen, { delay: 200 })
// Content only mounts if isOpen stays true for 200ms

Eager Mode

Use the eager option to render content immediately without waiting for activation:

ts
const { hasContent } = useLazy(isOpen, { eager: true })
// hasContent.value is always true

The eager option accepts a reactive value for dynamic control:

ts
const props = defineProps<{ eager: boolean }>()
const { hasContent } = useLazy(isOpen, {
  eager: toRef(() => props.eager),
})

Transition Integration

The onAfterLeave callback resets the lazy state after the leave transition completes (unless eager mode is enabled):

vue
<template>
  <Transition @after-leave="onAfterLeave">
    <div v-if="isOpen">
      <template v-if="hasContent">
        <!-- Heavy content -->
      </template>
    </div>
  </Transition>
</template>

This allows memory to be reclaimed when the content is hidden, while preserving the content during the leave animation.

FAQ

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

API Reference

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

Ctrl+/