A Vue formatter for single-file components
A .vue file mixes three languages: an HTML-based template, a JavaScript or TypeScript script, and CSS (often SCSS or LESS). This Vue formatter runs Prettier's vue parser, which splits the file into its blocks and formats each one with the matching parser: Vue template rules for <template>, Babel or TypeScript for <script> depending on lang="ts", and PostCSS for <style>.
Example: a Vue 3 component with script setup
<script setup>import {ref,computed} from 'vue';const todos=ref([]);const left=computed(()=>todos.value.filter(t=>!t.done).length)</script>
<template><ul><li v-for="t in todos" :key="t.id" :class="{done:t.done}" @click="t.done=!t.done">{{t.text}}</li></ul><p>{{left}} left</p></template>
<script setup>
import { ref, computed } from "vue";
const todos = ref([]);
const left = computed(() => todos.value.filter((t) => !t.done).length);
</script>
<template>
<ul>
<li
v-for="t in todos"
:key="t.id"
:class="{ done: t.done }"
@click="t.done = !t.done"
>
{{ t.text }}
</li>
</ul>
<p>{{ left }} left</p>
</template>
The script block is formatted as JavaScript, so it gets semicolons and double quotes. Directive values such as :class and @click are parsed as expressions and spaced consistently, and mustache interpolations gain inner spaces.
Vue template syntax handled
- Directives:
v-if/v-else-if/v-else,v-forwithinorof,v-modelwith modifiers,v-bindandv-onshorthands (:and@). - Slots:
v-slotand the#default="{ item }"shorthand with destructuring. - Dynamic arguments such as
:[attrName]="value". - Components in PascalCase or kebab-case; self-closing component tags are kept.
Script and style blocks
Both the Options API (export default { data() { ... } }) and the Composition API with <script setup> are supported. With lang="ts" the block is parsed as TypeScript, so defineProps<{ title: string }>() and typed refs are formatted correctly. Style blocks with scoped or module attributes are formatted as CSS; add lang="scss" or lang="less" for preprocessor syntax. Vue 3's v-bind() inside CSS, as in color: v-bind(themeColor), is kept as an ordinary CSS function.
Options and conventions
Indent defaults to 2 spaces, the convention in the official Vue style guide examples and in projects created with create-vue. Line width controls when attributes are split one per line. Prettier does not indent the contents of <script> and <style> blocks by default (its vueIndentScriptAndStyle option is off), which keeps diffs smaller when code moves between files.
Block order is preserved. The Vue style guide recommends a consistent order (script, template, style is common in Vue 3), but reordering is up to you; the formatter never moves blocks.
What Prettier leaves to eslint-plugin-vue
Prettier only decides layout. Several Vue conventions that look like formatting are really lint rules in eslint-plugin-vue: the order of attributes (v-for before v-if before bindings), PascalCase component names in templates, and whether components are self-closing. Prettier never reorders attributes or renames tags. If you use both tools, add eslint-config-prettier so stylistic ESLint rules such as vue/max-attributes-per-line do not fight with the formatter.
Common errors
- "Element is missing end tag" – Vue templates must close every non-void element. Self-closing
<MyComponent />is fine. - Errors inside the script block are reported with the line number within the whole file, so you can jump straight to it.
- Type annotations in a plain
<script>fail; addlang="ts". v-ifandv-foron the same element is valid syntax, so it formats, but the Vue style guide recommends moving the condition to a wrapper or a computed list.
Formatting runs locally in your browser. For stand-alone style files use the SCSS Formatter, and for plain TypeScript modules the TypeScript Formatter.