# Vue Conventions

> Vue/Nuxt code conventions for SFC structure, props, state, template directives, and composables. Load whenever writing or editing Vue Single-File Components (.vue) or Nuxt-specific code anywhere in this repo — components, pages, layouts, composables, or plugins. Use when this capability is needed.

- Skill: `tomevault-io/vue-conventions-2` (Agent Skill, multi-file: 2 files)
- Install (CLI): `npx skillmds@latest add tomevault-io/vue-conventions-2`
- Raw SKILL.md: https://api.skillmd.com/api/skills/tomevault-io/vue-conventions-2/raw
- Safety review: pending (external: skill-scanner PASS, skillspector PASS)
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Web & Frontend
- Author: tomevault-io (https://skillmd.com/u/tomevault-io)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/tomevault-io/vue-conventions-2

---


# Vue/Nuxt Code Conventions

Apply these whenever creating or modifying `.vue` files or Nuxt composables/plugins in this repo.

## Vue SFC Structure

- ALWAYS place `<template>` first in the SFC, before `<script>` and `<style>`.
- ALWAYS use `<script setup lang="ts">`.
- PREFER grouping by logical concern, not by type (data/methods/computed).

## Props & State

- ALWAYS use TypeScript type-based `defineProps()`, never runtime `PropType`.
- ALWAYS use type-based `defineEmits()`, never runtime array syntax.
- ALWAYS destructure props directly from `defineProps()` for reactivity + inline defaults. Do not use `withDefaults` or assign to a `props` variable. If the script uses no props, call `defineProps()` without destructuring.
- ALWAYS use same-name shorthand `:propName` instead of `:propName="propName"`.
- NEVER mutate props or their nested properties; emit changes to the parent.
- ALWAYS keep computed properties pure — no mutations, no async, no logging.
- USE `defineModel()` for two-way binding instead of manual prop+emit pairs.
- PREFER `ref()` over `reactive()` for state.
- PREFER VueUse composables over custom browser/DOM/state implementations (e.g. `useEventListener` over manual `addEventListener` + cleanup). `@vueuse/nuxt` is installed and auto-imports.

## Template Directives

- ALWAYS use `v-for="item of items"`, never `v-for="item in items"`.

## Composables

- PREFER `toValue()` to accept refs, getters, or plain values as input in shared composables.
- PREFER grouping composable code by concern/feature, not by Vue API type.
- PREFER extracting calculations to pure helper functions; the composable only handles reactivity.
- PREFER plain utility functions over composables unless reactivity or lifecycle hooks are needed. Expose state; let components handle presentation.

---
> Source: [lttr/jedlik-nejedlik](https://github.com/lttr/jedlik-nejedlik) — distributed by [TomeVault](https://tomevault.io).
<!-- tomevault:4.0:skill_md:2026-05-24 -->

