Loading source
Pulling the file list, source metadata, and syntax-aware rendering for this listing.
Source from repo
Vue 3.5+ Composition API reference with progressive sub-file loading for components, composables, reactivity, and testing.
Files
Skill
Size
Entrypoint
Format
Open file
Syntax-highlighted preview of this file as included in the skill package.
references/directives.md
1---2name: Custom Directives3description: Create reusable directives for low-level DOM manipulation4---56# Custom Directives78Custom directives provide low-level DOM access for reusable behavior.910## When to Use1112Use custom directives when:1314- You need direct DOM manipulation15- The behavior can't be achieved with components or composables16- You need to apply behavior to native elements1718## Basic Example1920```vue21<script setup lang="ts">22// v-focus directive23const vFocus = {24mounted: (el: HTMLElement) => el.focus()25}26</script>2728<template>29<input v-focus />30</template>31```3233## Directive Hooks3435```ts36const myDirective = {37// Before element attributes/listeners are applied38created(el, binding, vnode) {},3940// Before element is inserted into DOM41beforeMount(el, binding, vnode) {},4243// After element and children are mounted44mounted(el, binding, vnode) {},4546// Before parent component updates47beforeUpdate(el, binding, vnode, prevVnode) {},4849// After parent component updates50updated(el, binding, vnode, prevVnode) {},5152// Before parent component unmounts53beforeUnmount(el, binding, vnode) {},5455// After parent component unmounts56unmounted(el, binding, vnode) {}57}58```5960## Hook Arguments6162```ts63interface DirectiveBinding<T = any> {64value: T // v-my-dir="value"65oldValue: T // Previous value (beforeUpdate/updated only)66arg?: string // v-my-dir:arg67modifiers: Record<string, boolean> // v-my-dir.foo.bar → { foo: true, bar: true }68instance: ComponentPublicInstance // Component using the directive69dir: ObjectDirective // Directive definition object70}71```7273Example usage:7475```vue-html76<div v-example:foo.bar="baz">77```7879```ts80// binding object:81{82arg: 'foo',83modifiers: { bar: true },84value: /* value of baz */,85oldValue: /* previous value */86}87```8889## Function Shorthand9091When you only need `mounted` and `updated` with same behavior:9293```ts94// Full form95const vColor = {96mounted(el, binding) {97el.style.color = binding.value98},99updated(el, binding) {100el.style.color = binding.value101}102}103104// Shorthand (same behavior)105const vColor = (el: HTMLElement, binding: DirectiveBinding<string>) => {106el.style.color = binding.value107}108```109110## Global Registration111112```ts113// main.ts114const app = createApp(App)115116app.directive('focus', {117mounted: (el) => el.focus()118})119120// Shorthand121app.directive('color', (el, binding) => {122el.style.color = binding.value123})124```125126## Object Literals127128Pass multiple values:129130```vue-html131<div v-demo="{ color: 'white', text: 'hello' }">132```133134```ts135const vDemo = (el: HTMLElement, binding: DirectiveBinding<{ color: string; text: string }>) => {136console.log(binding.value.color) // 'white'137console.log(binding.value.text) // 'hello'138}139```140141## Dynamic Arguments142143```vue-html144<div v-my-directive:[dynamicArg]="value">145```146147## Practical Examples148149### v-click-outside150151```ts152const vClickOutside = {153mounted(el: HTMLElement, binding: DirectiveBinding<() => void>) {154el._clickOutside = (event: MouseEvent) => {155if (!el.contains(event.target as Node)) {156binding.value()157}158}159document.addEventListener('click', el._clickOutside)160},161unmounted(el: HTMLElement) {162document.removeEventListener('click', el._clickOutside)163}164}165```166167### v-tooltip168169```ts170const vTooltip = {171mounted(el: HTMLElement, binding: DirectiveBinding<string>) {172el.setAttribute('title', binding.value)173},174updated(el: HTMLElement, binding: DirectiveBinding<string>) {175el.setAttribute('title', binding.value)176}177}178```179180### v-permission181182```ts183const vPermission = {184mounted(el: HTMLElement, binding: DirectiveBinding<string>) {185if (!hasPermission(binding.value)) {186el.parentNode?.removeChild(el)187}188}189}190```191192## TypeScript: Global Directives193194```ts195// directives/highlight.ts196import type { Directive } from 'vue'197198export type HighlightDirective = Directive<HTMLElement, string>199200declare module 'vue' {201export interface ComponentCustomProperties {202vHighlight: HighlightDirective203}204}205206export default {207mounted: (el, binding) => {208el.style.backgroundColor = binding.value209}210} satisfies HighlightDirective211```212213## Usage on Components214215⚠️ **Not recommended** - directives apply to root element, which can be unpredictable with multi-root components.216217```vue-html218<!-- Applies to MyComponent's root element -->219<MyComponent v-my-directive />220```221222<!--223Source references:224- https://vuejs.org/guide/reusability/custom-directives.html225-->226