Single-File Components
Vue’s most distinctive feature is the Single-File Component (SFC) — a .vue file that contains a component’s logic, template, and styles in one place. This is how all Vue components in this course are written.
The three blocks
Section titled “The three blocks”A .vue file has up to three top-level blocks:
<script setup lang="ts">// Component logic: imports, reactive state, functions</script>
<template> <!-- Component HTML template --></template>
<style scoped>/* Component CSS — scoped to this component only */</style>Each block is optional, but in practice almost every component has all three.
The <script setup> block
Section titled “The <script setup> block”<script setup> is the Composition API’s shorthand. Everything declared inside it is automatically available in the template — no return statement needed.
<script setup lang="ts">import { ref } from 'vue'import PersonCard from './PersonCard.vue'
const name = ref('Alice')const greeting = `Hello, ${name.value}!`</script>The lang="ts" attribute enables TypeScript. Without it, the script block is plain JavaScript.
Anything imported in <script setup> — components, functions, types — is available directly in the template. Vue registers PersonCard automatically when you import it here.
The <template> block
Section titled “The <template> block”The template is standard HTML extended with Vue-specific syntax. It can only have one root element in Vue 2, but Vue 3 supports multiple root elements (fragments):
<template> <h1>{{ name }}</h1> <p>Welcome to FamilyTree</p></template>Vue compiles this template into a render function — a JavaScript function that describes what the DOM should look like. When reactive data changes, Vue re-runs the render function and efficiently patches the DOM.
Scoped styles
Section titled “Scoped styles”The scoped attribute on <style> makes CSS rules apply only to elements in this component’s template:
<style scoped>h1 { color: var(--accent); font-size: 1.5rem;}</style>Under the hood, Vue adds a unique data attribute (like data-v-3f8a2c) to your component’s elements and rewrites the CSS to target that attribute. A .card rule in one component won’t affect .card elements in other components.
If you need global styles, use a separate CSS file imported in main.ts, or remove the scoped attribute.
A complete example
Section titled “A complete example”Here’s a PersonCard component that shows a name and birth year:
<script setup lang="ts">defineProps<{ name: string birthYear?: number}>()</script>
<template> <div class="card"> <span class="name">{{ name }}</span> <span v-if="birthYear" class="year">b. {{ birthYear }}</span> </div></template>
<style scoped>.card { display: flex; gap: 0.5rem; padding: 0.5rem 0.75rem; border: 1px solid var(--border); border-radius: 6px;}.name { font-weight: 600; }.year { color: var(--text-muted); font-size: 0.85rem; }</style>This is a complete, self-contained component. Its styles won’t leak. Its logic is co-located with its template. This is what makes SFCs such an effective authoring format.
Exercise
Section titled “Exercise”- In your project, create
src/components/GreetingCard.vue. - Give it a
nameprop (string) and amessageprop (string). - Display both in the template inside a styled card div.
- Import and use
<GreetingCard>insrc/App.vue, passing values for both props. - Add scoped styles that give the card a border and padding.
- A
.vueSFC has three blocks:<script setup>,<template>, and<style scoped>. <script setup lang="ts">is the Composition API shorthand — everything declared is available in the template.<template>is standard HTML + Vue syntax; Vue 3 supports multiple root elements.scopedstyles only apply to the current component — no style leakage between components.- Imported components are automatically registered in
<script setup>— nocomponents: {}option needed.