Skip to main content
Vuetify0 v1.0 is here
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

Scrim

Headless backdrop component for overlay systems with automatic z-index management and dismiss handling.

Edit this page
Report a Bug
Open issues
View on GitHub
Copy Markdown

PreviewRenders elementIntermediateJul 19, 2026

Installation

The Scrim component uses the global stack context. For SSR applications, install the stack plugin:

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. The Scrim will use the default stack singleton automatically.

Usage

The Scrim component renders a backdrop that appears when any overlay is active. It automatically positions itself below the topmost overlay using z-index management from the stack context.

Important

The scrim is rendered with aria-hidden — it is decorative. Don’t place interactive or focusable content in its default slot; keep controls inside the overlay itself.

<script setup lang="ts">
  import { provide, shallowRef, watch } from 'vue'
  import { createStack, Scrim } from '@vuetify/v0'

  const stack = createStack()
  provide('v0:stack', stack)

  const open = shallowRef(false)
  const ticket = stack.register({
    onDismiss: () => {
      open.value = false
    },
    blocking: false,
  })

  watch(open, v => v ? ticket.select() : ticket.unselect())

  const blocking = shallowRef(false)
  const blockingTicket = stack.register({
    onDismiss: () => {
      blocking.value = false
    },
    blocking: true,
  })

  watch(blocking, v => v ? blockingTicket.select() : blockingTicket.unselect())
</script>

<template>
  <div class="flex gap-3 justify-center">
    <button
      class="px-4 py-2 bg-primary text-on-primary rounded-md text-sm font-medium"
      @click="open = true"
    >
      Open Overlay
    </button>

    <button
      class="px-4 py-2 bg-error text-on-error rounded-md text-sm font-medium"
      @click="blocking = true"
    >
      Open Blocking
    </button>
  </div>

  <Scrim
    class="fixed inset-0 bg-black/50"
    :teleport="false"
  />

  <div
    v-if="open"
    class="fixed inset-0 flex items-center justify-center pointer-events-none"
    :style="{ zIndex: ticket.zIndex.value }"
  >
    <div class="rounded-xl bg-surface border border-divider p-6 max-w-sm w-full shadow-lg pointer-events-auto">
      <h3 class="text-lg font-semibold text-on-surface mb-2">
        Dismissible Overlay
      </h3>

      <p class="text-sm text-on-surface-variant mb-4">
        Click the scrim backdrop to dismiss this overlay.
      </p>

      <button
        class="px-4 py-2 text-sm font-medium rounded-md border border-divider hover:bg-surface-tint"
        @click="open = false"
      >
        Close
      </button>
    </div>
  </div>

  <div
    v-if="blocking"
    class="fixed inset-0 flex items-center justify-center pointer-events-none"
    :style="{ zIndex: blockingTicket.zIndex.value }"
  >
    <div class="rounded-xl bg-surface border border-divider p-6 max-w-sm w-full shadow-lg pointer-events-auto">
      <h3 class="text-lg font-semibold text-on-surface mb-2">
        Blocking Overlay
      </h3>

      <p class="text-sm text-on-surface-variant mb-4">
        This overlay blocks scrim dismissal. You must use the button to close it.
      </p>

      <button
        class="px-4 py-2 text-sm font-medium rounded-md bg-error text-on-error"
        @click="blocking = false"
      >
        Confirm Close
      </button>
    </div>
  </div>
</template>

Anatomy

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

<template>
  <Scrim />
</template>

Recipes

Blocking Mode

When the topmost overlay has blocking: true, the scrim will not dismiss on click. The isBlocking slot prop reflects this state:

vue
<template>
  <Scrim v-slot="{ isBlocking }" class="fixed inset-0">
    <div :class="isBlocking ? 'bg-black/70' : 'bg-black/50'" />
  </Scrim>
</template>

Inline Rendering

By default, Scrim teleports to body. Disable teleport for inline rendering:

vue
<template>
  <div class="relative">
    <Scrim :teleport="false" class="absolute inset-0 bg-black/50" />
    <!-- Content -->
  </div>
</template>

Custom Stack Context

For isolated overlay systems, create a custom stack and provide it via Vue’s injection system:

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

  // Create isolated stack (doesn't interfere with global stack)
  const stack = createStack()
  provide('v0:stack', stack)
</script>

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

Transitions

The default transition is fade. Customize with the transition prop:

vue
<template>
  <Scrim transition="slide-fade" class="fixed inset-0 bg-black/50" />
</template>

<style>
  .slide-fade-enter-active,
  .slide-fade-leave-active {
    transition: opacity 0.3s ease;
  }

  .slide-fade-enter-from,
  .slide-fade-leave-to {
    opacity: 0;
  }
</style>

Accessibility

Scrim renders each backdrop layer with aria-hidden="true", so assistive technology skips it entirely — the scrim is decorative and must never hold focusable or interactive content. Its only behavior is click-to-dismiss (suppressed when the topmost overlay is blocking), which is a pointer convenience, not the accessible dismissal path.

The accessible dismissal contract — Escape-to-close, focus trapping, and focus return — belongs to the overlay the scrim sits behind, not to the scrim itself. Pair Scrim with Dialog, which owns role="dialog", focus management, and keyboard handling; the scrim only paints the backdrop.

FAQ

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

API Reference

The following API details are for all variations of the Scrim component.
Was this page helpful?

© 2016-1970 Vuetify, LLC
Services
Ctrl+/