Created
September 18, 2025 13:39
-
-
Save danielkellyio/cd1d3261b8c6a39fd02d97446a6bb209 to your computer and use it in GitHub Desktop.
Vue Cursor Rules
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| --- | |
| globs: **/*.vue,**/*.ts,**/*.js | |
| alwaysApply: false | |
| --- | |
| # Vue 3 Best Practices & Rules | |
| ## General Rules | |
| ALWAYS use the Composition API with `<script setup>` syntax. | |
| ALWAYS use Typescript. | |
| ALWAYS type props, emits, and model values. | |
| NEVER use any. Prefer unknown and narrow types explicitly. | |
| Avoid redundant refs: if you can derive state with computed, don't store extra refs. | |
| ## Code Style | |
| Use early returns whenever possible to make the code more readable. | |
| ALWAYS follow the single responsibility principle: | |
| - Components handle rendering and presentation only. Move logic, state, and side effects into composables. | |
| - Composables handle logic and state only. Do not include rendering or DOM concerns. | |
| - Utilities handle pure, stateless functions only. Do not use Vue reactivity here. | |
| - For small, single-use composables, declare them inline in a component's <script setup> block. | |
| ## Components | |
| ### Structure | |
| The sections should be in the following order, and only include the sections that are needed: | |
| - <script setup lang="ts"> | |
| - <template> | |
| - <style scoped> | |
| In the <script setup> section, follow @general-ts.mdc rules. | |
| ### Naming | |
| ALWAYS use PascalCase for component names. | |
| ### Best Practices | |
| ALWAYS use camelCase in <script setup> for props and emits | |
| ALWAYS use kebab-case in templates for props and emits | |
| ALWAYS use useTemplateRef('refName') to use refs in templates. | |
| ALWAYS use defineModel<type>() to define v-model bindings. Do not use modelValue prop and update:modelValue event manually | |
| Prefer built-in event modifiers @click.stop and @click.prevent over manual event.stopPropagation() and event.preventDefault() in script. | |
| ### Using defineEmits | |
| ALWAYS define component emits with `defineEmits<{ camelCaseName: [argOne: string, argTwo: number] }>()` | |
| Use `const emit =` ONLY if emits are used in the script block | |
| Inside templates, use `$emit('event', argOne)` to emit events | |
| ### Props | |
| ALWAYS define props with defineProps<{ camelCaseName: string }>() | |
| Only add `const props =` when props are used in the <script> block | |
| ALWAYS destructure props to declare default values. Do not use withDefaults | |
| ```ts | |
| // Good | |
| defineProps<{ | |
| myProp: number | |
| }>() | |
| // Bad: props is not used in the script block | |
| const props = defineProps<{ | |
| myProp: number | |
| }>() | |
| ``` | |
| ```ts | |
| // Good: props is used in the script block | |
| const props = defineProps<{ | |
| myProp: number | |
| }>() | |
| console.log(props.myProp) | |
| ``` | |
| ```ts | |
| // Good: default value is assigned | |
| const { myProp = 0 } = defineProps<{ | |
| propOne?: number | |
| }>() | |
| console.log(myProp) | |
| ``` | |
| ### Watching Props Requires a Getter Function | |
| ALWAYS use a getter function when watching props. | |
| ```ts | |
| // Bad | |
| watch(props.propOne, (newVal) => { | |
| console.log(newVal) | |
| }) | |
| // Good | |
| watch( | |
| () => props.propOne, | |
| (newVal) => { | |
| console.log(newVal) | |
| }, | |
| ) | |
| ``` | |
| ## Composables | |
| ### Naming | |
| ALWAYS use camelCase for composable names. | |
| ALWAYS start the name with `use` prefix. | |
| ### Best Practices | |
| Prefer using `MaybeRefOrGetter` and `toValue` when passing reactive data to composables. | |
| Prefer using objects as function arguments instead of multiple arguments. | |
| Example: | |
| ```ts | |
| // Good | |
| myFunction({ arg1: 'value1', arg2: 'value2' }) | |
| // Bad | |
| myFunction('value1', 'value2') | |
| ``` |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment