plugins/smedjen/skills/vue-patterns/SKILL.md
Vue 3 Composition API, reactivity system, Pinia state management, and Vue 2→3 migration patterns.
npx skillsauth add hjemmesidekongen/ai vue-patternsInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
When to extract: logic uses 2+ reactive primitives together and appears in multiple components. Single ref() doesn't warrant a composable.
Return shape: always return an object ({ data, loading, error, refresh }), never a single ref. Allows destructuring and future extension without breaking callers.
Naming: use prefix, noun-oriented (useAuth, useFormValidation). Name describes the concern, not the implementation. Composables can call other composables — keep chains shallow (max 3 levels).
Cleanup: if a composable sets up listeners/timers/subscriptions, use onUnmounted internally. Callers shouldn't need to remember cleanup.
Use for cross-cutting concerns needing 3+ levels of prop drilling: theme, locale, feature flags, form context. Testing benefit: provide in test wrappers replaces real services with mocks. Use InjectionKey<T> for type safety.
Scope control: provide at the nearest common ancestor, not app root — root-level provide is effectively a global (use Pinia instead). Always provide a fallback in inject('key', defaultValue) or throw explicitly.
defineModel(): two-way binding without manual emit boilerplate. const model = defineModel<string>() replaces the modelValue prop + update:modelValue emit pair. Supports named models: defineModel('title').
defineSlots(): type-safe slot definitions. Enforces slot prop types at compile time. Use in library components where consumers need slot prop documentation.
defineExpose(): explicitly declare what ref on the component can access. Default in <script setup> is nothing exposed. Only expose imperative methods (focus, reset, validate) — never expose internal state.
Hydration mismatch: server and client must render identical initial HTML. Common causes: Date.now(), Math.random(), browser-only APIs (window, localStorage), conditional rendering based on screen size.
Fix pattern: <ClientOnly> wrapper for browser-dependent content. For data: use useState() (Nuxt) which serializes server state to __NUXT_DATA__ for client hydration.
Serialization limits: provide/inject values aren't serialized across SSR boundary. Pinia state is (via useNuxtApp().payload). Plan store shape around what's JSON-serializable.
onMounted is client-only: any DOM measurement, intersection observer, or animation setup must go in onMounted. Code at <script setup> top-level runs on both server and client.
Plugins: pinia.use(({ store }) => { store.$subscribe(...) }). Common uses: persistence (pinia-plugin-persistedstate), undo/redo (track mutation history), logging.
Store composition: stores can import and use other stores. useCartStore calls useProductStore().getProduct(id). Avoid circular dependencies — extract shared logic to a composable instead.
See references/process.md for reactivity pitfalls, slots, Teleport, Suspense, and anti-patterns.
development
Creates a brand from scratch through market research and interactive sparring. Runs competitive research via Perplexity, then guides the user through positioning, audience, voice, values, and content pillars. Produces the full brand guideline set at .ai/brand/{name}/. Use when building a new brand, defining brand strategy for a product, or when /våbenskjold:create is invoked.
testing
Loads brand guidelines from .ai/brand/{name}/ and makes them available to the current context. Progressive disclosure: L1 confirms brand exists, L2 loads summary, L3 loads specific files on demand. Use when a downstream skill or user needs brand context, or when /våbenskjold:apply is invoked.
documentation
Guided reinvention of an existing brand guideline. Loads current brand from .ai/brand/{name}/, identifies what to keep vs change, and walks the user through targeted evolution. Preserves brand equity while updating positioning, voice, or values. Use when refreshing a brand or when /våbenskjold:evolve is invoked.
development
Codifies an existing brand from materials, samples, and references. Analyzes provided content to extract voice patterns, values, and positioning. Produces the same guideline format as brand-strategy. Use when a brand already exists but isn't documented, or when /våbenskjold:audit is invoked.