Skip to content

v-click-outside

Detect clicks outside an element. Perfect for closing dropdowns, modals, and popovers.

Since: 1.0.0

Usage

Basic

vue
<template>
  <div v-click-outside="closeDropdown">
    <button @click="show = !show">Toggle</button>
    <div v-if="show">Dropdown content</div>
  </div>
</template>

<script setup>
import { ref } from 'vue'

const show = ref(false)

function closeDropdown(event) {
  show.value = false
}
</script>

With Options

vue
<template>
  <div v-click-outside="{
    handler: closeDropdown,
    exclude: ['.trigger', ignoreButton],
    events: ['click', 'touchstart']
  }">
    <button class="trigger">Toggle</button>
    <button :ref="ignoreButton">This is ignored</button>
  </div>
</template>

API

Types

typescript
type ClickOutsideHandler = (event: MouseEvent | TouchEvent) => void

interface ClickOutsideOptions {
  /** Callback when clicking outside (required) */
  handler: ClickOutsideHandler
  /** Excluded element selectors or element references */
  exclude?: (string | HTMLElement | (() => HTMLElement | null))[]
  /** Whether to use capture mode */
  capture?: boolean
  /** Event types to listen for */
  events?: ('click' | 'mousedown' | 'mouseup' | 'touchstart' | 'touchend')[]
  /** Whether to disable */
  disabled?: boolean
  /** Stop propagation */
  stop?: boolean
  /** Prevent default behavior */
  prevent?: boolean
}

type ClickOutsideBinding = ClickOutsideHandler | ClickOutsideOptions

Options

OptionTypeDefaultDescription
handlerFunction-Callback when click outside detected (required)
exclude(string | HTMLElement | Function)[][]Elements to exclude from detection
capturebooleantrueUse capture mode
eventsstring[]['click']Events to listen for
disabledbooleanfalseDisable the directive
stopbooleanfalseStop event propagation
preventbooleanfalsePrevent default behavior

Examples

vue
<template>
  <div v-click-outside="closeMenu" class="dropdown">
    <button @click="isOpen = !isOpen">
      {{ isOpen ? 'Close' : 'Open' }} Menu
    </button>
    <ul v-if="isOpen" class="menu">
      <li @click="selectItem('item1')">Item 1</li>
      <li @click="selectItem('item2')">Item 2</li>
      <li @click="selectItem('item3')">Item 3</li>
    </ul>
  </div>
</template>

<script setup>
import { ref } from 'vue'

const isOpen = ref(false)

function closeMenu() {
  isOpen.value = false
}

function selectItem(item) {
  console.log('Selected:', item)
  closeMenu()
}
</script>
vue
<template>
  <div v-if="showModal" class="modal-overlay">
    <div v-click-outside="closeModal" class="modal">
      <h2>Modal Title</h2>
      <p>Modal content here...</p>
      <button @click="closeModal">Close</button>
    </div>
  </div>
</template>

<script setup>
import { ref } from 'vue'

const showModal = ref(false)

function closeModal() {
  showModal.value = false
}
</script>

Exclude Elements

vue
<template>
  <div v-click-outside="{
    handler: closeDropdown,
    exclude: ['.toggle-btn', triggerRef]
  }">
    <button class="toggle-btn" @click="toggle">Toggle</button>
    <div v-if="isOpen" class="dropdown-content">
      Content
    </div>
  </div>
</template>

<script setup>
import { ref } from 'vue'

const isOpen = ref(false)
const triggerRef = ref(null)

function toggle() {
  isOpen.value = !isOpen.value
}

function closeDropdown() {
  isOpen.value = false
}
</script>

Composable API

For programmatic use, you can use the useClickOutside composable:

typescript
import { useClickOutside } from 'directix'

const { bind } = useClickOutside({
  handler: (event) => {
    console.log('Clicked outside')
  },
  exclude: ['.trigger', () => triggerRef.value],
  events: ['click'],
  capture: true,
  stop: false,
  prevent: false
})

// Bind to element
onMounted(() => {
  const unbind = bind(dropdownRef.value)
  onUnmounted(unbind)
})

UseClickOutsideOptions

OptionTypeDefaultDescription
handler(event: MouseEvent | TouchEvent) => void-Callback when clicking outside (required)
exclude(string | HTMLElement | Function | Ref)[][]Excluded element selectors or references
capturebooleantrueUse capture mode
eventsstring[]['click']Event types to listen for
stopbooleanfalseStop event propagation
preventbooleanfalsePrevent default behavior

UseClickOutsideReturn

PropertyTypeDescription
bind(element: HTMLElement) => () => voidBind click outside detection to an element

Example

vue
<script setup>
import { ref } from 'vue'
import { useClickOutside } from 'directix'

const dropdown = ref(null)
const show = ref(false)

const { bind } = useClickOutside({
  handler: () => show.value = false,
  exclude: [() => triggerRef.value]
})

onMounted(() => bind(dropdown.value))
</script>

<template>
  <div ref="dropdown">
    <button @click="show = !show">Toggle</button>
    <div v-if="show">Dropdown content</div>
  </div>
</template>

Code Generator

Quick Code Generator
<template>
  <div v-click-outside="{ handler: 'handleClickOutside', capture: true, disabled: false }">
    <!-- Detect clicks outside an element directive -->
  </div>
</template>

<script setup lang="ts">
import { ref } from 'vue'

// Configure your options here
const options = { handler: 'handleClickOutside', capture: true, disabled: false }
</script>

Released under the MIT License.