Vue Single File Components

By

Learn how Vue 3 single file components keep template, script, and CSS in one .vue file, with script setup, Vite scaffolding, and scoped styles.

~~~

A Vue component can live in a plain JavaScript file, or in a .vue file.

The .vue file is the usual choice. It lets you define

all in one place. That is a Single File Component.

Here is a Vue 3 example with <script setup>, the recommended style today:

<template>
  <p>{{ hello }}</p>
</template>

<script setup>
import { ref } from 'vue'

const hello = ref('Hello World!')
</script>

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

The Options API still works if you prefer it:

<template>
  <p>{{ hello }}</p>
</template>

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

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

Scaffolding with Vite

.vue files need a build step, because the browser does not understand them. New projects use Vite, and the official scaffolder sets it up for you:

npm create vue@latest

That creates a Vue 3 + Vite app. You do not need a hand-rolled webpack setup for new work, and you do not need the old Vue CLI either, which is in maintenance mode.

Single File Components are the natural choice for SPAs and any app that has a frontend build. If you only add Vue to one page of a server-rendered site, you can still load Vue from a CDN and write inline templates, but then you can’t use .vue files.

Preprocessors and modern JS

Because Vite (or another bundler) processes the file, you can use preprocessors.

Your CSS can use SCSS or Stylus, the template can use Pug. You declare the language on the block with the lang attribute:

<style lang="scss" scoped>
  $color: blue;
  p {
    color: $color;
  }
</style>

Supported preprocessors include

You install the preprocessor as a devDependency (sass, less, pug) and Vite picks it up. No extra configuration.

You can also use modern JavaScript and ES Modules (import / export) without worrying about the target browser. Vite transpiles the code for the browsers you target at build time.

Scoped CSS

<style scoped> keeps CSS inside the component. Vue adds a unique attribute to the elements and rewrites the selectors so styles do not leak out.

Omit scoped, and the CSS is global.

Externalize script or style

If the script grows too big, point to another file with src. This works with a plain <script> block that exports the component options:

<template>
  <p>{{ hello }}</p>
</template>
<script src="./hello.js"></script>

<script setup> does not accept src. With <script setup>, keep the block inline and import your logic from another file instead.

Same idea for CSS:

<template>
  <p>{{ hello }}</p>
</template>
<script src="./hello.js"></script>
<style scoped src="./hello.css"></style>

A note on data and arrow functions

With the Options API, data must be a function that returns an object:

export default {
  data() {
    return {
      hello: 'Hello World!'
    }
  }
}

Avoid arrow functions for data, methods, and similar options when you need this. Arrow functions do not bind this to the component instance.

With <script setup>, you skip that pattern. Top-level bindings are exposed to the template automatically.

Tagged: Vue.js · All topics

Want me to talk about your product? You can sponsor this site.

~~~

Related posts about vue: