On this page
Single File Components: script setup, template, and scoped styles
The Single File Component format
A Single File Component (SFC) is a file with the .vue extension that collocates three concerns in one place:
<script setup>— component logic written in TypeScript<template>— the HTML-based markup<style scoped>— CSS styles that are automatically scoped to this component
This co-location is Vue's most celebrated design decision. You do not have to jump between three different files to understand a single component; everything is right there. Bundlers like Vite compile SFCs into efficient JavaScript via @vitejs/plugin-vue.
The `
lang=ts is required for TypeScript
Always add lang="ts" to your <script setup> tag. Without it, Vue treats the block as plain JavaScript and type checking is disabled.
scoped styles and child components
Scoped styles only affect elements in the current component. They do NOT penetrate child component roots. Use the :deep() combinator or global styles to style child component internals.
Volar extension
Install the official Vue — Official extension (formerly Volar) in VS Code. It provides full TypeScript support, template type checking, and intelligent autocomplete for SFCs.
<script setup lang="ts">
// 1. Imports at the top
import { ref, computed } from 'vue'
// 2. Props (covered in depth in lesson 6)
const props = defineProps<{
name: string
role: string
avatarUrl?: string
}>()
// 3. Local state
const isExpanded = ref(false)
// 4. Derived state
const initials = computed(() =>
props.name
.split(' ')
.map(w => w[0])
.join('')
.toUpperCase()
)
// 5. Methods — plain functions, no special syntax
function toggleExpanded() {
isExpanded.value = !isExpanded.value
}
</script>
<template>
<article class="card" :class="{ expanded: isExpanded }">
<div class="avatar">
<img v-if="avatarUrl" :src="avatarUrl" :alt="name" />
<span v-else aria-hidden="true">{{ initials }}</span>
</div>
<div class="info">
<h2>{{ name }}</h2>
<p>{{ role }}</p>
</div>
<button type="button" @click="toggleExpanded">
{{ isExpanded ? 'Collapse' : 'Expand' }}
</button>
</article>
</template>
<style scoped>
.card {
display: flex;
align-items: center;
gap: 1rem;
padding: 1rem;
border: 1px solid #e2e8f0;
border-radius: 0.5rem;
transition: box-shadow 0.2s;
}
.card.expanded {
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
}
.avatar {
width: 3rem;
height: 3rem;
border-radius: 50%;
background: #41b883;
display: grid;
place-items: center;
color: white;
font-weight: bold;
overflow: hidden;
}
</style>
Sign in to track your progress