--- description: Load Vue component patterns and best practices --- # Vue Component Priming > **Note:** This command references the `nuxt:nuxt` skill for progressive disclosure of additional Vue patterns and library-specific documentation. ## Script Setup Syntax ALWAYS use ` ``` ### Component Naming - ALWAYS use multi-word component names except for Nuxt pages and layouts - Examples: `UserProfile.vue`, `SearchBar.vue` (not `User.vue`, `Search.vue`) - Exception: `pages/index.vue`, `pages/about.vue`, `layouts/default.vue` ## Template Directives ### v-for Loops ALWAYS use `key` in v-for loops and prefer `of` over `in`: ```vue
  • {{ user.name }}
  • {{ user.name }}
  • {{ user.name }}
  • ``` ### Prop Binding Shorthand ALWAYS use shorthand syntax when passing props with same name as variable: ```vue ``` ## Reactivity and State ### Reactive References PREFER `ref()` for reactive state instead of `reactive()`: ```typescript // ✅ Preferred: Using ref const count = ref(0) const user = ref({ name: "Alice", age: 30 }) // ❌ Less preferred: Using reactive (loses reactivity on destructure) const state = reactive({ count: 0 }) ``` ### Auto-Imported Vue APIs Never manually import these in Nuxt projects - they're auto-imported: **Reactivity:** - `ref` - Reactive primitive values - `reactive` - Reactive objects - `computed` - Computed values - `watch` - Watch reactive values **Lifecycle:** - `onMounted` - Component mounted - `onUnmounted` - Component unmounted - `onBeforeMount`, `onBeforeUnmount`, etc. **Component APIs:** - `defineProps` - Define props (type-based) - `defineEmits` - Define emits (type-based) - `defineModel` - Define v-model (type-based) **Utilities:** - `useId` - Generate unique IDs for accessibility/form elements (SSR-safe) ## Component Organization ### Logical Grouping PREFER to group by logical concerns rather than by type: ```typescript // ✅ Preferred: Grouped by feature/concern // ❌ Less preferred: Grouped by type ``` ## Styling Strategy **Check `package.json` for `@nuxtjs/tailwindcss`:** ### If Tailwind Installed ```vue ``` ### If NO Tailwind ALWAYS use `
    Title
    ``` ## VueUse Composables (If Installed) Check `package.json` for `@vueuse/core` or `@vueuse/nuxt`: PREFER VueUse composables over custom implementations for common tasks: ```typescript // ✅ Preferred: Using VueUse (if installed) import { useLocalStorage, useMouse, useWindowSize } from "@vueuse/core" const token = useLocalStorage("auth-token", "") // ❌ Avoid: Custom implementation when VueUse exists const token = ref(localStorage.getItem("auth-token") || "") watch(token, (val) => localStorage.setItem("auth-token", val)) ``` ### Common VueUse Patterns **State:** - `useToggle`, `useCounter`, `useLocalStorage`, `useSessionStorage` **DOM:** - `useMouse`, `useScroll`, `useElementVisibility`, `useIntersectionObserver`, `useResizeObserver` **Browser:** - `useClipboard`, `useMediaQuery`, `useDark`, `usePreferredDark`, `useGeolocation` **Utilities:** - `refDebounced`, `useDebounceFn`, `refThrottled`, `useThrottleFn`, `useInterval`, `useTimeout` The `nuxt:nuxt` skill provides detailed VueUse reference when installed. ## Accessibility - Use semantic HTML: ` ``` ### Slots ```vue ``` ## Provide/Inject For dependency injection: ```typescript // Parent component provide("theme", "dark") provide("api", apiClient) // Child component (any depth) const theme = inject("theme") const api = inject("api") // With TypeScript import type { InjectionKey } from "vue" interface Theme { mode: "light" | "dark" } const themeKey: InjectionKey = Symbol("theme") // Provide provide(themeKey, { mode: "dark" }) // Inject const theme = inject(themeKey) ``` ## Lifecycle Hooks ```typescript // Setup (reactive state initialization) const count = ref(0) // Mounted (DOM available) onMounted(() => { console.log("Component mounted") }) // Before unmount (cleanup) onBeforeUnmount(() => { // Remove event listeners, clear timers, etc. }) // Unmounted onUnmounted(() => { console.log("Component unmounted") }) // Watch effect (runs immediately and on dependencies change) watchEffect(() => { console.log(`Count is ${count.value}`) }) // Watch specific value watch(count, (newValue, oldValue) => { console.log(`Count changed from ${oldValue} to ${newValue}`) }) ``` ## Template Refs ```vue ```