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

useClickOutside

A composable for detecting clicks outside of specified element(s) with automatic cleanup.

Usage

The useClickOutside composable detects when users click outside target elements. It uses two-phase detection (pointerdown → pointerup) to prevent false positives when dragging, and includes touch scroll handling for mobile.

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

  const menu = useTemplateRef('menu')

  useClickOutside(menu, () => {
    console.log('Clicked outside the menu')
  })
</script>

<template>
  <div ref="menu">
    Menu content
  </div>
</template>

Architecture

useClickOutside builds on useEventListener for pointer and focus event detection:

Click Outside Hierarchy

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

Click Outside Hierarchy

Options

OptionTypeDefaultDescription
boundsbooleanfalseUse bounding-rect detection instead of DOM containment. Required for native <dialog> elements — backdrop clicks have the <dialog> as the event target, so containment checks always pass
ts
import { useClickOutside } from '@vuetify/v0'

const dialog = useTemplateRef('dialog')

// For native <dialog> — backdrop clicks are detected via coordinates
useClickOutside(dialog, () => dialog.value?.close(), { bounds: true })

Reactivity

Property/MethodReactiveNotes
isActiveComputed from !isPaused
isPausedShallowRef, readonly
pause()-Stop detection, preserve state
resume()-Resume detection
stop()-Stop and clean up listeners

Examples

A three-item dropdown menu that opens on button click and automatically closes when the user clicks anywhere outside the menu container. The entire menu div — trigger button and panel together — is passed as the target ref, so clicking the trigger itself is treated as “inside” and doesn’t trigger the dismiss callback.

The example uses useClickOutside in its simplest form: one ref target and one callback. No options are needed because the target is a regular div (not a native <dialog>), so the default DOM-containment check works correctly. The callback flips isOpen.value = false, and because isOpen is a shallowRef, the template re-renders without a full reactive traversal.

Reach for this when dismissing a popover, dropdown, or context menu on outside click. For elements where the event target doesn’t reliably reflect DOM containment — such as native <dialog> backdrops — pass { bounds: true } to switch to bounding-rect detection instead.

Recipes

Multiple Targets

Pass an array of refs to ignore clicks inside any of them:

ts
import { useClickOutside } from '@vuetify/v0'
import { useTemplateRef } from 'vue'

const trigger = useTemplateRef('trigger')
const panel = useTemplateRef('panel')

// Clicks inside EITHER trigger or panel are ignored
useClickOutside([trigger, panel], () => {
  console.log('Clicked outside both elements')
})

The target parameter accepts MaybeArray<ClickOutsideTarget> — a single ref/getter or an array of refs/getters.

FAQ

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

API Reference

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

Ctrl+/