Skip to main content
Vuetify0 is now in alpha!
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

useStack


IntermediateApr 5, 2026

Overlay z-index coordinator with automatic stacking order and parent-child nesting support.

Installation

Install the Stack plugin in your app’s entry point:

main.ts
import { createApp } from 'vue'
import { createStackPlugin } from '@vuetify/v0'
import App from './App.vue'

const app = createApp(App)

app.use(createStackPlugin())

app.mount('#app')
Tip

For client-side only apps, you can skip plugin installation and use the default stack singleton directly. The plugin is required for SSR to ensure each request gets its own stack instance.

Usage

Use the useStack composable to register an overlay and receive its z-index and position in the stack:

ts
import { shallowRef, watch } from 'vue'
import { useStack } from '@vuetify/v0'

const isOpen = shallowRef(false)

const stack = useStack()
const ticket = stack.register({
  onDismiss: () => { isOpen.value = false }
})

// Activate when opening, deactivate when closing
watch(isOpen, open => {
  if (open) ticket.select()
  else ticket.unselect()
})

// ticket.zIndex.value = 2000 when first overlay
// ticket.zIndex.value = 2010 when second overlay
// ticket.globalTop.value = true when this is the topmost overlay

Context / DI

Use createStackContext when you need a separate z-index namespace (e.g., overlays inside a modal):

ts
import { createStackContext } from '@vuetify/v0'

const [useModalStack, provideModalStack, modalStack] =
  createStackContext({ namespace: 'my:modal-stack', baseZIndex: 3000 })

// In parent component
provideModalStack()

// In child overlay component
const stack = useModalStack()
const ticket = stack.register({ id: 'tooltip-1' })
ticket.zIndex.value  // z-index for this overlay

Architecture

createStack extends createRegistry with z-index management and scrim coordination:

Stack Hierarchy

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

Stack Hierarchy

Reactivity

Stack state and ticket properties are reactive for automatic UI updates.

PropertyReactiveNotes
isActiveAny overlays selected
topTopmost overlay ticket
scrimZIndexZ-index for scrim element
isBlockingTop overlay blocks dismissal
ticket zIndexComputed from selection order
ticket globalTopTrue if topmost
ticket isSelectedOverlay active state

Examples

Overlay Stack

This example demonstrates overlay stacking with createStack. Each overlay gets an automatically calculated z-index, and the scrim appears below the topmost overlay.

Stack Data Flow

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

Stack Data Flow

File breakdown:

FileRole
context.tsDefines overlay context with open/close methods
StackProvider.vueProvides stack context and renders scrim
StackConsumer.vueDisplays buttons to open overlays at different stack levels
overlays.vueEntry point that composes Provider around Consumer

Key patterns:

  • stack.register({ onDismiss }) creates a ticket for the overlay

  • ticket.select() / ticket.unselect() activates/deactivates the overlay

  • ticket.globalTop determines if this overlay should handle escape key

  • ticket.zIndex provides the z-index value

  • Scrim reads from the stack context to position below the top overlay

Click a button to open an overlay. Open multiple overlays to observe z-index layering.

Stack:
empty

Scrim Integration

Use the Scrim component alongside useStack to provide a backdrop for your overlays. The Scrim automatically positions itself below the topmost overlay:

vue
<script setup lang="ts">
import { Scrim } from '@vuetify/v0'
</script>

<template>
  <Scrim class="fixed inset-0 bg-black/50" />
</template>

The Scrim reads from the same stack context, so its z-index is always coordinated with your registered overlays.

API Reference

The following API details are for the useStack composable.

Functions

createStack

(_options?: StackOptions) => StackContext<StackTicketInput, StackTicket<StackTicketInput>>

Creates a new stack instance for managing overlay z-indexes.

createStackContext

(_options?: StackContextOptions) => ContextTrinity<StackContext<StackTicketInput, StackTicket<StackTicketInput>>>

Creates a stack context trinity for provide/inject usage.

createStackPlugin

(_options?: StackPluginOptions) => import("/home/runner/work/0/0/packages/0/src/composables/index").Plugin

Creates a Vue plugin to provide stack context at app level.

useStack

(namespace?: string) => StackContext<StackTicketInput, StackTicket<StackTicketInput>>

Returns the current stack context.

Options

events

boolean | undefined

Enable event emission for registry operations

Default: false

reactive

boolean | undefined

Enable reactive behavior for registry operations

Default: false

disabled

MaybeRefOrGetter<boolean> | undefined

Disabled state for the entire model instance

Default: false

enroll

MaybeRefOrGetter<boolean> | undefined

Auto-select tickets on registration

Default: true

multiple

MaybeRefOrGetter<boolean> | undefined

Allow multiple tickets to be selected simultaneously

Default: false

mandatory

MaybeRefOrGetter<boolean | "force"> | undefined

Controls mandatory selection behavior: - `false` (default): No mandatory selection enforcement - `true`: Prevents deselecting the last selected item - `'force'`: Automatically selects the first non-disabled item on registration

baseZIndex

number | undefined

Base z-index when stack is empty

Default: 2000

increment

number | undefined

Z-index increment between overlays

Default: 10

Properties

collection

ReadonlyMap<ID, E>

The collection of tickets in the registry

size

number

The number of tickets in the registry

selectedIds

Reactive<Set<ID>>

Set of currently selected ticket IDs

selectedItems

ComputedRef<Set<E>>

Computed Set of selected ticket instances

selectedValues

ComputedRef<Set<E["value"] extends Ref<infer U, infer U> ? U : E["value"]>>

Computed Set of selected ticket values

disabled

MaybeRefOrGetter<boolean>

Disabled state for the entire model instance

multiple

MaybeRefOrGetter<boolean>

Whether the selection allows multiple selections

isActive

Readonly<Ref<boolean, boolean>>

Whether any overlays are selected (active)

top

Readonly<Ref<E | undefined, E | undefined>>

The topmost selected overlay ticket

scrimZIndex

Readonly<Ref<number, number>>

Z-index for the scrim (one below top overlay)

isBlocking

Readonly<Ref<boolean, boolean>>

Whether the topmost overlay blocks scrim clicks

Methods

clear

() => void

Clear the entire registry

has

(id: ID) => boolean

Check if a ticket exists by ID

keys

() => readonly ID[]

Get all registered IDs

browse

(value: E["value"]) => ID[] | undefined

Browse for an ID(s) by value

lookup

(index: number) => ID | undefined

lookup a ticket by index number

get

(id: ID) => E | undefined

Get a ticket by ID

upsert

(id: ID, ticket?: Partial<Z>, event?: string) => E

Update or insert a ticket by ID

values

() => readonly E[]

Get all values of registered tickets

entries

() => readonly [ID, E][]

Get all entries of registered tickets

unregister

(id: ID) => void

Unregister a ticket by ID

reindex

() => void

Reset the index directory and update all tickets

move

(id: ID, toIndex: number) => E | undefined

Seek for a ticket based on direction and optional predicate

seek

(direction?: "first" | "last", from?: number, predicate?: (ticket) => boolean) => E | undefined

on

<K extends Extensible<RegistryEventName>>(event: K, cb: EventHandler<E, K>) => void

Listen for registry events

off

<K extends Extensible<RegistryEventName>>(event: K, cb: EventHandler<E, K>) => void

Stop listening for registry events

emit

<K extends Extensible<RegistryEventName>>(event: K, data: EventPayload<E, K>) => void

Emit an event with data

dispose

() => void

Clears the registry and removes all listeners

onboard

(registrations: Partial<Z & RegistryTicket>[]) => E[]

Onboard multiple tickets at once

offboard

(ids: ID[]) => void

Offboard multiple tickets at once

batch

<R>(fn: () => R) => R

Execute operations in a batch, deferring cache invalidation and event emission until complete

reset

() => void

Reset selection state without destroying the registry

select

(id: ID) => void

Select a ticket by ID

unselect

(id: ID) => void

Unselect a ticket by ID

toggle

(id: ID) => void

Toggle a ticket's selection state

selected

(id: ID) => boolean

Check if a ticket is currently selected

apply

(values: unknown[], options?: { multiple?) => void

Apply external values to the model

mandate

() => void

Mandate selected ID based on "mandatory" option

register

(input?: Partial<Z>) => E

Register an overlay ticket

Was this page helpful?

© 2016-1970 Vuetify, LLC
Ctrl+/