# SFC Syntax Specification

# Intro

A *.vue file is a custom file format that uses HTML-like syntax to describe a Vue component. Each *.vue file consists of three types of top-level language blocks: <template>, <script>, and <style>, and optionally additional custom blocks:

<template>
  <div class="example">{{ msg }}</div>
</template>

<script>
export default {
  data() {
    return {
      msg: 'Hello world!'
    }
  }
}
</script>

<style>
.example {
  color: red;
}
</style>

<custom1>
  This could be e.g. documentation for the component.
</custom1>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23

# Language Blocks

# <template>

  • Each *.vue file can contain at most one top-level <template> block at a time.

  • Contents will be extracted and passed on to @vue/compiler-dom, pre-compiled into JavaScript render functions, and attached to the exported component as its render option.

# <script>

  • Each *.vue file can contain at most one <script> block at a time (excluding <script setup>).

  • The script is executed as an ES Module.

  • The default export should be a Vue component options object, either as a plain object or as the return value of defineComponent.

# <script setup>

  • Each *.vue file can contain at most one <script setup> block at a time (excluding normal <script>).

  • The script is pre-processed and used as the component's setup() function, which means it will be executed for each instance of the component. Top-level bindings in <script setup> are automatically exposed to the template. For more details, see dedicated documentation on <script setup>.

# <style>

  • A single *.vue file can contain multiple <style> tags.

  • A <style> tag can have scoped or module attributes (see SFC Style Features for more details) to help encapsulate the styles to the current component. Multiple <style> tags with different encapsulation modes can be mixed in the same component.

# Custom Blocks

Additional custom blocks can be included in a *.vue file for any project-specific needs, for example a <docs> block. Some real-world examples of custom blocks include:

Handling of Custom Blocks will depend on tooling - if you want to build your own custom block integrations, see SFC Tooling for more details.

# Automatic name Inference

An SFC automatically infers the component's name from its filename in the following cases:

  • Dev warning formatting
  • DevTools inspection
  • Recursive self-reference. E.g. a file named FooBar.vue can refer to itself as <FooBar/> in its template. This has lower priority than explicity registered/imported components.

# Pre-Processors

Blocks can declare pre-processor languages using the lang attribute. The most common case is using TypeScript for the <script> block:

<script lang="ts">
  // use TypeScript
</script>
1
2
3

lang can be applied to any block - for example we can use <style> with SASS (opens new window) and <template> with Pug (opens new window):

<template lang="pug">
p {{ msg }}
</template>

<style lang="scss">
  $primary-color: #333;
  body {
    color: $primary-color;
  }
</style>
1
2
3
4
5
6
7
8
9
10

Note the intergration with pre-processors may differ based on the toolchain. Check out the respective documentations for examples:

# Src Imports

If you prefer splitting up your *.vue components into multiple files, you can use the src attribute to import an external file for a language block:

<template src="./template.html"></template>
<style src="./style.css"></style>
<script src="./script.js"></script>
1
2
3

Beware that src imports follow the same path resolution rules as webpack module requests, which means:

  • Relative paths need to start with ./
  • You can import resources from npm dependencies:
<!-- import a file from the installed "todomvc-app-css" npm package -->
<style src="todomvc-app-css/index.css">
1
2

src imports also work with custom blocks, e.g.:

<unit-test src="./unit-test.js">
</unit-test>
1
2

# Comments

Inside each block you shall use the comment syntax of the language being used (HTML, CSS, JavaScript, Pug, etc.). For top-level comments, use HTML comment syntax: <!-- comment contents here -->