Vue components are reusable, self-contained building blocks that package markup, JavaScript logic, and CSS together. Instead of writing one giant HTML file, you split your interface into small components like headers, cards, and buttons.
In modern Vue 3 projects, each component lives in a .vue Single File Component (SFC). An SFC keeps related code together while isolating styles so one component never breaks another.
flowchart TD
App["App.vue"] --> Header["AppHeader.vue"]
App --> Main["DashboardView.vue"]
Main --> Card1["MetricCard.vue"]
Main --> Card2["MetricCard.vue"]
.vue Single File Component<script setup>: Runs when the component initializes. Any imported component or top-level variable is available directly in the template.<template>: Holds the HTML structure and Vue directives. Vue 3 supports multiple root elements in a template.<style scoped>: Adds unique attributes at compile time so CSS rules apply only to elements in this component.First, create a reusable child component MetricCard.vue that receives title and value via defineProps().
<script setup>
defineProps({
title: String,
value: [String, Number]
});
</script>
<template>
<div class="metric-card">
<h3>{{ title }}</h3>
<p class="value">{{ value }}</p>
</div>
</template>
<style scoped>
.metric-card {
padding: 1rem;
border-radius: 6px;
background-color: #ffffff;
border: 1px solid #e2e8f0;
}
.value {
font-size: 1.5rem;
font-weight: bold;
color: #2c3e50;
}
</style>
Next, import and render MetricCard inside App.vue. With <script setup>, importing the file automatically registers it for template use.
<script setup>
import MetricCard from './components/MetricCard.vue';
</script>
<template>
<main class="dashboard">
<h2>Dashboard Overview</h2>
<div class="grid">
<MetricCard title="Total Sales" value="$42,500" />
<MetricCard title="Active Users" :value="1280" />
</div>
</main>
</template>
Card.vue or Header.vue can collide with native or future HTML elements. Always use multi-word PascalCase names like MetricCard.vue or AppHeader.vue.scoped on Styles: Omitting scoped makes CSS rules global across the entire app, causing unexpected style leaks.<script setup> rather than module-level variables unless you intentionally want all instances to share one variable.<div>?No. Vue 3 supports fragments, so a <template> can contain multiple sibling elements at the top level without an extra wrapper <div>.
components: { MetricCard } when using <script setup>?No. Importing a .vue component inside <script setup> registers it in the template automatically.
Split a section into a new component when you repeat that UI pattern across pages or when a single .vue file becomes hard to read and test.
Sign in to track your learning journey, earn industry-recognized certificates, and join our elite developer community.
Quick Access With