# Vue Component Best Practices
These patterns apply to Vue 3+ and modern Nuxt applications.
## Script Setup Syntax
ALWAYS use `
// ✅ Correct: No props used in script
// ❌ Wrong: Runtime PropType syntax
import type { PropType } from 'vue'
defineProps({
items: {
type: Array as PropType,
required: true
}
})
```
### Emits
ALWAYS use type-based syntax for `defineEmits` in TypeScript instead of runtime array syntax.
```typescript
// ✅ Correct: Type-based emits
const emit = defineEmits<{
update: [value: string]
close: []
}>()
// ❌ Wrong: Runtime array syntax
const emit = defineEmits(["update", "close"])
```
### Event Handler Typing
When emitting events with event objects, use appropriate event types:
```typescript
// ✅ Correct: Typed event handlers
const emit = defineEmits<{
click: [event: MouseEvent]
keypress: [event: KeyboardEvent]
input: [event: InputEvent]
submit: [event: SubmitEvent]
}>()
// Usage in template
```
### v-model
USE `defineModel()` for v-model implementations instead of manually defining props and emits.
```typescript
// ✅ Correct: Using defineModel
const modelValue = defineModel()
// ❌ Wrong: Manual prop + emit
const props = defineProps<{ modelValue: string }>()
const emit = defineEmits<{ "update:modelValue": [value: string] }>()
```
## Component Structure
### Template Placement
ALWAYS place the `` section at the top of Vue SFC files, before `
```
### 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` are acceptable
## Template Directives
### v-for Loops
- ALWAYS use `key` in v-for loops
- ALWAYS use `v-for="item of items"` instead of `v-for="item in items"` to match JavaScript `for...of` syntax
```vue
{{ user.name }}
{{ user.name }}
{{ user.name }}
```
### Prop Binding Shorthand
ALWAYS use shorthand syntax (`:propName`) when passing a prop with the same name as the variable, instead of verbose form (`:propName="propName"`).
```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
const state = reactive({ count: 0 })
```
### VueUse Composables
PREFER VueUse composables and utility functions over custom implementations for common tasks like state management, DOM interactions, and browser APIs.
Check if `@vueuse/core` or `@vueuse/nuxt` is installed before suggesting VueUse composables.
```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))
```
## Component Organization
### Logical Grouping
PREFER to group by logical concerns rather than grouping by type (data, methods, computed) within components. Keep related state, computed properties, and functions together.
```typescript
// ✅ Preferred: Grouped by feature/concern
// ❌ Less preferred: Grouped by type
```
## Styling
ALWAYS use `