Single-file components
A single-file component (SFC) is a file with the .vue extension that holds everything one part of the interface needs: markup, JavaScript code and styles. Vite turns such a file into a regular JavaScript module.
Three blocks
Replace src/App.vue:
<!-- src/App.vue -->
<script setup>
const title = 'My tasks'
</script>
<template>
<h1>{{ title }}</h1>
</template>
<style>
h1 {
color: #42b883;
}
</style>The page at http://localhost:5173 shows a green heading "My tasks". The text comes from the title variable.
| Block | What it holds | Required |
|---|---|---|
script setup | Variables, functions, imports | No |
template | HTML markup with Vue features | Almost always |
style | CSS for the component | No |
The order of blocks does not matter, but the script usually goes first: it shows which data the template uses.
The script setup block
The code inside <script setup> runs for every instance of the component. Everything declared at the top level of the block — variables, functions, imported values — is available in the template right away. You do not write export or return anything.
<script setup>
const owner = 'Anna'
function greet() {
return `Hello, ${owner}!`
}
</script>
<template>
<p>{{ greet() }}</p>
</template>The page shows "Hello, Anna!": the template called a function declared in the script.
The style scoped block
A plain style block applies to the whole page. The scoped attribute limits styles to the current component:
<style scoped>
h1 {
font-size: 32px;
}
</style>Vue adds a special attribute like data-v-7a7a37b1 to the component's elements and appends it to the selectors. h1 headings in other components do not change.
File name
Component files are named in PascalCase — every word capitalised, at least two words: TodoItem.vue, TodoForm.vue. The root App.vue is the exception. Two words keep a name from clashing with an existing HTML tag such as header or button.
Common mistake
The template sees only what is declared in <script setup>. If you write a plain <script> block without the word setup, its variables do not reach the template, and Vue prints a console warning like Property "title" was accessed during render but is not defined. Check that the script tag has the setup attribute.