From vue-best-practices
Vue 3 + TypeScript best practices. Load for any .vue file, composable, Pinia store, or Vue-related task in any Vue 3 project. Covers component decomposition, composable patterns, provide/inject, Pinia, reactivity, SFC structure, and file size and architecture rules. Based on vuejs-ai/skills vue-best-practices.
How this skill is triggered — by the user, by Claude, or both
Slash command
/vue-best-practices:vue-best-practicesThe summary Claude sees in its skill listing — used to decide when to auto-load this skill
Stack: Vue 3 + `<script setup lang="ts">` + Pinia + Vitest. Read this before writing any `.vue` file or composable.
Stack: Vue 3 + <script setup lang="ts"> + Pinia + Vitest. Read this before writing any .vue file or composable.
computed..vue file is approaching 500 lines, look for what to extract next.Before writing any non-trivial component, sketch the component map:
components/<Feature>/, composables/use<Feature>.ts.Split a component when any of these are true:
Don't extract when:
Read references/reactivity.md before working with reactive state.
Key rules:
shallowRef() for primitives, ref() when you replace the whole value, reactive() when you mutate in place.computed() for all derived values — never watchEffect + manual assignment.watch().immediate: true instead of duplicating initial calls in onMounted.shallowRef for objects, call triggerRef() after mutating nested properties.Read references/sfc.md before writing .vue files.
Key rules:
<script setup> → <template> → <style scoped>.<style scoped> for component styles; class selectors only (not element selectors).v-if and v-for on the same element — use a computed filter.:key in v-for — prefer item.id, never index for stateful lists.Read references/component-data-flow.md before wiring components together.
Key rules:
InjectionKey<T> is the right pattern when a subtree needs shared context without prop drilling — not 40 props. See references/component-data-flow.md for the typed pattern.defineProps<Props>(), defineEmits<Emits>(), InjectionKey<T>.v-model via defineModel() for two-way bindings (Vue 3.4+).Recommended provide/inject pattern:
// useXxxContext.ts
import type { InjectionKey } from 'vue'
export interface XxxContext { /* all state + actions the subtree needs */ }
export const XXX_CTX_KEY: InjectionKey<XxxContext> = Symbol('xxxContext')
export function provideXxxContext(ctx: XxxContext) {
provide(XXX_CTX_KEY, ctx)
}
export function useXxxContext(): XxxContext {
const ctx = inject(XXX_CTX_KEY)
if (!ctx) throw new Error('useXxxContext must be used inside XxxProvider')
return ctx
}
Use this pattern whenever a parent component owns state that multiple children need — instead of passing it as props.
Read references/composables.md before writing useX functions.
Key rules:
utils/, not composables.readonly() state and explicit action functions — consumers should not mutate composable internals directly.Large modal layers extracted from view components use the provide/inject pattern:
useXxxModalContext.ts — typed InjectionKey<XxxModalContext> with provideXxxModalContext and useXxxModalContext.XxxModalsLayer.vue — zero props, uses useXxxModalContext() to inject all state. Contains all modal/dialog/overlay declarations for that view.provideXxxModalContext(...) and renders <XxxModalsLayer /> — no modal imports needed in the view itself.This keeps view components thin and makes the modal layer independently readable.
ref/reactive or composables.shallowRef + triggerRef for large normalized maps for performance.storeToRefs() — reactivity breaks.Every hardcoded value needs a named constant — including:
const TAB_SWITCH_FIT_VIEW_DELAY_MS = 50)Run the project's test command (e.g. npm test, npm run test:unit, vitest) after every change. All tests must pass before committing.
setActivePinia(createPinia()) in beforeEach, localStorage.clear() if the store reads from localStorage on init.npx claudepluginhub signalcanvas/signalcanvas-skills --plugin vue-best-practicesCreates, edits, and optimizes skills for Claude Code, including drafting, evaluating with test prompts, iterating on performance, and improving skill descriptions for better triggering accuracy.