Skip to content

SFC Authoring Rules

10.4.1. Block Order

Blocks within an SFC (Single File Component) must follow this order:

  1. <script setup lang="ts"> — Logic
  2. <template> — Markup
  3. <style scoped> — Styles
vue
<script setup lang="ts">
import { ref } from 'vue'

const message = ref('Hello')
</script>

<template>
  <p>{{ message }}</p>
</template>

<style scoped>
p {
  color: inherit;
}
</style>

Required

The ESLint vue/block-order rule enforces this order. Violations will trigger a lint error.


10.4.2. Template Authoring Rules

  • v-html must not be used. It is vulnerable to XSS attacks. If unavoidable, sanitize the content with DOMPurify before use.
  • v-for must always have a :key binding. Do not use index as the key.
  • v-if and v-for must not be used on the same element. Separate them using a <template> tag.
vue
<!-- Correct -->
<template v-for="item in items" :key="item.id">
  <div v-if="item.isActive">
    {{ item.name }}
  </div>
</template>

<!-- Incorrect -->
<div v-for="item in items" v-if="item.isActive" :key="item.id">
  {{ item.name }}
</div>

10.4.3. Attribute Binding Rules

  • Static attributes must be written as plain HTML attributes; dynamic attributes must use the v-bind (:) shorthand.
  • Boolean attributes must be declared without a value to pass true.
  • When there are 3 or more attributes, place one attribute per line.
vue
<!-- 3 or more attributes — one per line -->
<UserCard
  :user="currentUser"
  :editable="isAdmin"
  :loading="isLoading"
  @update="handleUpdate"
/>

<!-- Boolean attributes -->
<BaseButton
  primary
  disabled
  @click="handleClick"
/>

10.4.4. Event Handling

  • Event handlers must use the @ shorthand. Do not use v-on.
  • Inline handlers are permitted only for simple expressions (single line).
  • Complex logic must be extracted into a separate function.
vue
<script setup lang="ts">
function handleSubmit() {
  // Complex logic
}
</script>

<template>
  <!-- Correct: simple expression -->
  <button @click="count++">Increment</button>

  <!-- Correct: function reference -->
  <form @submit.prevent="handleSubmit">
    <!-- ... -->
  </form>
</template>

10.4.5. Style Rules

  • The <style> tag must always use scoped. Global styles must be managed in the src/styles/ directory.
  • The :deep() selector should be used only sparingly, limited to overriding child component styles.
  • Tailwind CSS utility classes should be used preferentially; custom CSS must be minimized.
vue
<style scoped>
/* Scoped styles */
.container {
  @apply flex items-center gap-4;
}

/* Child component style override (limited use) */
:deep(.child-class) {
  color: inherit;
}
</style>

TIENIPIA QUALIFIED STANDARD