---
name: vue-development
description: Vue 3 development with Composition API, reactivity system, component patterns, TypeScript integration, and best practices.
allowed-tools: Read, Write, Edit, Bash, Glob, Grep
---
# Vue Development Skill
Expert assistance for building Vue 3 applications with Composition API and modern patterns.
## Capabilities
- Create Vue 3 components with Composition API
- Implement reactive state with ref and reactive
- Build composables for reusable logic
- Configure TypeScript with Vue
- Set up Vue Router and navigation guards
- Implement provide/inject for dependency injection
## Usage
Invoke this skill when you need to:
- Create Vue 3 components
- Build composables for shared logic
- Set up Vue project structure
- Implement reactive patterns
- Configure Vue with TypeScript
## Inputs
| Parameter | Type | Required | Description |
|-----------|------|----------|-------------|
| componentName | string | Yes | Component name (PascalCase) |
| compositionApi | boolean | No | Use Composition API (default: true) |
| typescript | boolean | No | Use TypeScript (default: true) |
| scriptSetup | boolean | No | Use script setup (default: true) |
### Configuration Example
```json
{
"componentName": "UserProfile",
"compositionApi": true,
"typescript": true,
"scriptSetup": true,
"features": ["props", "emits", "slots"]
}
```
## Component Patterns
### Script Setup Component
```vue
{{ initials }}
```
### Composable Pattern
```typescript
// composables/useUser.ts
import { ref, computed, readonly } from 'vue';
interface User {
id: string;
name: string;
email: string;
}
export function useUser(userId: string) {
const user = ref(null);
const loading = ref(false);
const error = ref(null);
const isAuthenticated = computed(() => !!user.value);
async function fetchUser() {
loading.value = true;
error.value = null;
try {
const response = await fetch(`/api/users/${userId}`);
if (!response.ok) throw new Error('Failed to fetch user');
user.value = await response.json();
} catch (e) {
error.value = e as Error;
} finally {
loading.value = false;
}
}
async function updateUser(data: Partial) {
if (!user.value) return;
loading.value = true;
try {
const response = await fetch(`/api/users/${userId}`, {
method: 'PATCH',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(data),
});
user.value = await response.json();
} catch (e) {
error.value = e as Error;
} finally {
loading.value = false;
}
}
return {
user: readonly(user),
loading: readonly(loading),
error: readonly(error),
isAuthenticated,
fetchUser,
updateUser,
};
}
// composables/useLocalStorage.ts
import { ref, watch } from 'vue';
export function useLocalStorage(key: string, defaultValue: T) {
const stored = localStorage.getItem(key);
const data = ref(stored ? JSON.parse(stored) : defaultValue);
watch(
data,
(newValue) => {
localStorage.setItem(key, JSON.stringify(newValue));
},
{ deep: true }
);
return data;
}
```
### Provide/Inject Pattern
```typescript
// context/theme.ts
import { provide, inject, ref, type Ref, type InjectionKey } from 'vue';
type Theme = 'light' | 'dark';
interface ThemeContext {
theme: Ref;
toggleTheme: () => void;
}
const ThemeKey: InjectionKey = Symbol('theme');
export function provideTheme() {
const theme = ref('light');
function toggleTheme() {
theme.value = theme.value === 'light' ? 'dark' : 'light';
}
provide(ThemeKey, { theme, toggleTheme });
return { theme, toggleTheme };
}
export function useTheme() {
const context = inject(ThemeKey);
if (!context) {
throw new Error('useTheme must be used within a theme provider');
}
return context;
}
```
### Vue Router Setup
```typescript
// router/index.ts
import { createRouter, createWebHistory } from 'vue-router';
import type { RouteRecordRaw } from 'vue-router';
const routes: RouteRecordRaw[] = [
{
path: '/',
component: () => import('@/layouts/DefaultLayout.vue'),
children: [
{
path: '',
name: 'home',
component: () => import('@/views/Home.vue'),
},
{
path: 'dashboard',
name: 'dashboard',
component: () => import('@/views/Dashboard.vue'),
meta: { requiresAuth: true },
},
],
},
{
path: '/login',
name: 'login',
component: () => import('@/views/Login.vue'),
},
];
const router = createRouter({
history: createWebHistory(),
routes,
});
// Navigation guard
router.beforeEach((to, from, next) => {
const isAuthenticated = !!localStorage.getItem('token');
if (to.meta.requiresAuth && !isAuthenticated) {
next({ name: 'login', query: { redirect: to.fullPath } });
} else {
next();
}
});
export default router;
```
## Best Practices
- Use script setup for cleaner components
- Create composables for reusable logic
- Type props and emits properly
- Use readonly for exposed reactive state
- Leverage provide/inject for deep dependency passing
## Target Processes
- vue-application-development
- vue-component-library
- nuxt-full-stack
- frontend-architecture