---
description: Creates Vue 3 Single File Components (SFC) using Composition API with <script setup>. Use when creating new Vue components, refactoring options API to composition API, or building UI components with Vue 3.
---

# Vue 3 Component Creator

Create Vue 3 SFC components following these conventions:

## Structure

Every component must use `<script setup>` syntax with Composition API (no Options API, no TypeScript).

```
<ComponentName>.vue
├── <script setup>  — imports, props, emits, reactive state, methods
├── <template>      — HTML template
└── <style>         — (optional) scoped styles
```

## Rules

### Props and Emits
- Use `defineProps()` with object syntax for type declarations and defaults
- Use `defineEmits()` with array of event names: `defineEmits(['add', 'delete'])`
- Always provide default values for optional props
- Name emits as verbs: `@add`, `@toggle`, `@delete`, `@update`

### Reactive State
- Use `ref()` for primitive values and single objects
- Use `computed()` for derived state
- Use `watch()` with `{ deep: true }` when watching objects/arrays
- Never use `reactive()` — prefer `ref()` for consistency

### Styling Conventions
- **Layout & spacing**: Use Tailwind CSS utility classes (`flex`, `gap-4`, `mb-6`, `rounded-xl`, etc.)
- **Colors & shadows**: Use CSS custom properties via inline `style` bindings, NOT Tailwind color classes
  - `style="color: var(--text)"` — text color
  - `style="background: var(--surface)"` — background
  - `style="border-color: var(--border)"` — borders
  - `style="box-shadow: var(--shadow-md)"` — shadows
- This separation enables theme switching without Tailwind rebuilds

### Component Communication
- Parent → Child: props
- Child → Parent: emits (never use `provide/inject` for simple parent-child)
- Cross-component: composables (shared state via `ref()`)

### Expose
- Use `defineExpose()` only when parent needs imperative access (e.g., `focus()`)
- Keep exposed surface minimal

### Template Conventions
- Use `v-for` with `:key` always
- Use `v-if` / `v-show` appropriately (`v-if` for conditional rendering, `v-show` for frequent toggles)
- Destructure complex style bindings into computed or inline objects
- Prefer `@click` over `v-on:click`

## Template

Generate a Vue 3 SFC component following this pattern:

```vue
<!--
  ComponentName.vue — One-line description
  Features: list key features
-->
<script setup>
import { ref, computed, watch } from 'vue'

const props = defineProps({
  items: { type: Array, default: () => [] },
  active: { type: Boolean, default: false },
})

const emit = defineEmits(['select', 'delete'])

const localState = ref('')

const derivedValue = computed(() =>
  props.items.filter(item => item.active)
)

const handleAction = () => {
  emit('select', localState.value)
}
</script>

<template>
  <div class="flex flex-col gap-3"
       style="background: var(--surface); color: var(--text);">
    <div v-for="item in derivedValue" :key="item.id"
         class="px-4 py-2 rounded-lg transition-all duration-200"
         style="border: 1px solid var(--border);"
         @click="handleAction">
      {{ item.name }}
    </div>
  </div>
</template>
```
