Loading source
Pulling the file list, source metadata, and syntax-aware rendering for this listing.
Source from repo
Enforces Vue 3 Composition API best practices with script setup, TypeScript, Pinia, and Vite.
Files
Skill
Size
Entrypoint
Format
Open file
Syntax-highlighted preview of this file as included in the skill package.
references/directives.md
1---2title: Directive Best Practices3impact: MEDIUM4impactDescription: Custom directives are powerful but easy to misuse; following patterns prevents leaks, invalid usage, and unclear abstractions5type: best-practice6tags: [vue3, directives, custom-directives, composition, typescript]7---89# Directive Best Practices1011**Impact: MEDIUM** - Directives are for low-level DOM access. Use them sparingly, keep them side-effect safe, and prefer components or composables when you need stateful or reusable UI behavior.1213## Task List1415- Use directives only when you need direct DOM access16- Do not mutate directive arguments or binding objects17- Clean up timers, listeners, and observers in `unmounted`18- Register directives in `<script setup>` with the `v-` prefix19- In TypeScript projects, type directive values and augment template directive types20- Prefer components or composables for complex behavior2122## Treat Directive Arguments as Read-Only2324Directive bindings are not reactive storage. Don’t write to them.2526```ts27const vFocus = {28mounted(el, binding) {29// binding.value is read-only30el.focus()31}32}33```3435## Avoid Directives on Components3637Directives apply to DOM elements. When used on components, they attach to the root element and can break if the root changes.3839**BAD:**40```vue41<MyInput v-focus />42```4344**GOOD:**45```vue46<!-- MyInput.vue -->47<script setup>48const vFocus = (el) => el.focus()49</script>5051<template>52<input v-focus />53</template>54```5556## Clean Up Side Effects in `unmounted`5758Any timers, listeners, or observers must be removed to avoid leaks.5960```ts61const vResize = {62mounted(el) {63const observer = new ResizeObserver(() => {})64observer.observe(el)65el._observer = observer66},67unmounted(el) {68el._observer?.disconnect()69}70}71```7273## Prefer Function Shorthand for Single-Hook Directives7475If you only need `mounted`/`updated`, use the function form.7677```ts78const vAutofocus = (el) => el.focus()79```8081## Use the `v-` Prefix and Script Setup Registration8283```vue84<script setup>85const vFocus = (el) => el.focus()86</script>8788<template>89<input v-focus />90</template>91```9293## Type Custom Directives in TypeScript Projects9495Use `Directive<Element, ValueType>` so `binding.value` is typed, and augment Vue's template types so directives are recognized in SFC templates.9697**BAD:**98```ts99// Untyped directive value and no template type augmentation100export const vHighlight = {101mounted(el, binding) {102el.style.backgroundColor = binding.value103}104}105```106107**GOOD:**108```ts109import type { Directive } from 'vue'110111type HighlightValue = string112113export const vHighlight = {114mounted(el, binding) {115el.style.backgroundColor = binding.value116}117} satisfies Directive<HTMLElement, HighlightValue>118119declare module 'vue' {120interface ComponentCustomProperties {121vHighlight: typeof vHighlight122}123}124```125126## Handle SSR with `getSSRProps`127128Directive hooks such as `mounted` and `updated` do not run during SSR. If a directive sets attributes/classes that affect rendered HTML, provide an SSR equivalent via `getSSRProps` to avoid hydration mismatches.129130**BAD:**131```ts132const vTooltip = {133mounted(el, binding) {134el.setAttribute('data-tooltip', binding.value)135el.classList.add('has-tooltip')136}137}138```139140**GOOD:**141```ts142const vTooltip = {143mounted(el, binding) {144el.setAttribute('data-tooltip', binding.value)145el.classList.add('has-tooltip')146},147getSSRProps(binding) {148return {149'data-tooltip': binding.value,150class: 'has-tooltip'151}152}153}154```155156## Prefer Declarative Templates When Possible157158If a standard attribute or binding works, use it instead of a directive.159160## Decide Between Directives and Components161162Use a directive for DOM-level behavior. Use a component when behavior affects structure, state, or rendering.163