Vue.js: Component Basics

Last updated: 2026-10-20

A Vue component is a reusable Vue instance — every component encapsulates its own template, logic, and styles. The core architecture of Vue 3 is the "component tree": root component (App.vue) → page components → business components → base components (Button/Input).

Mastering component basics is a key step toward writing large Vue applications. This lesson helps you understand what a component really is, how to register one, the naming conventions, and why SFCs (Single-File Components) are the recommended way to write Vue.

1. What You'll Learn


2. The Code Duplication Disaster of a 30-Page E-commerce Admin

(1) Pain Point: 30 Product Cards, Copy-Pasted 30 Times

Alice's e-commerce admin needs to show 30 product cards across several pages. Her first approach:

HTML
<!-- ❌ Broken version: 30 product cards copied 30 times -->
<!-- In HomeView.vue -->
<div class="product-card">
  <img src="iphone.jpg">
  <h3>iPhone 15 Pro</h3>
  <p>$999</p>
  <button>Add to Cart</button>
</div>
<div class="product-card">
  <img src="macbook.jpg">
  <h3>MacBook Pro</h3>
  <p>$2499</p>
  <button>Add to Cart</button>
</div>
<!-- ... and 28 more ... -->

<!-- The same code shows up again in ProductList.vue, SearchResults.vue, Cart.vue -->

Product manager Charlie added 5 new requests:

"Alice, I want the button text changed from 'Add to Cart' to 'Add to Bag'. Also the card should show stock status. And it needs to be responsive on mobile."

Alice had to edit 30+ HTML files × 3 rounds = 90 edits. That is simply unmaintainable.

(2) The Vue Component Solution: 1 ProductCard.vue, 30 Reuses

1 ProductCard.vue → 30 reuses. Changing the button text means changing 1 place.

(3) Benefits

After componentizing:


3. What Is a Component?

(1) Definition

A component is a reusable UI unit with its own logic and styles in Vue. Each component = 1 Vue instance + its own data/methods/lifecycle.

100%
graph TB
    A[App.vue<br/>Root component] --> B[HomeView.vue<br/>Home page]
    A --> C[AboutView.vue<br/>About]
    A --> D[DashboardView.vue<br/>Dashboard]
    
    B --> E[ProductCard.vue<br/>Product card]
    B --> F[ProductList.vue<br/>Product list]
    B --> G[FilterBar.vue<br/>Filter bar]
    
    E --> H[Button.vue<br/>Button]
    E --> I[Badge.vue<br/>Badge]
    
    F --> E
    G --> J[Select.vue<br/>Select]
    G --> K[Input.vue<br/>Input]
    
    style A fill:#42b883,color:#fff
    style E fill:#42b883,color:#fff
    style H fill:#42b883,color:#fff

(2) 5 Core Characteristics

Characteristic Description
Reusable 1 component can be used in N places
Encapsulated Its own data / methods / style, independent of others
Composable Small components compose into large ones
Testable Unit-test a single component
Maintainable Change 1 place = change N places

(3) Components vs Functions

Dimension Function Component
Unit of reuse Code logic UI + logic
Input Arguments props
Output return emit
State Local variables data / refs
Side effects None Lifecycle hooks

▶ Example: Reusing ProductCard on 3 Pages

▶ Try it Yourself

Output:

TEXT
Three sections, each rendering the same ProductCard component with different data: Home Featured lists iPhone and MacBook, Product List All lists all three products, and Category Phones lists only the iPhone.
Every row prints the name plus a line such as $999 | Stock: 50, and no card markup is duplicated in the source.
TEXT
Home Featured
iPhone
$999 | Stock: 50
MacBook
$2499 | Stock: 20

Product List All
iPhone
$999 | Stock: 50
MacBook
$2499 | Stock: 20
iPad
$599 | Stock: 30

Category Phones
iPhone
$999 | Stock: 50

4. Single-File Components (SFC)

(1) What Is an SFC?

SFC (Single File Component) = 1 .vue file = 1 component. It keeps template, script, and style in a single file, which makes them easier to manage.

(2) The 3 Parts of an SFC

Part Purpose Required? Language
<template> HTML template ✅ HTML + Vue directives
<script setup> JS logic ✅ JavaScript / TypeScript
<style scoped> CSS styles ❌ CSS / SCSS / Less

(3) SFC vs HTML Strings

JS
// ❌ Without an SFC (string template, Vue 2 style)
Vue.component('my-component', {
  template: '<div>{{ msg }}</div>',
  data() { return { msg: 'Hello' } }
})

// ✅ With an SFC (recommended)
// MyComponent.vue
<template>
  <div>{{ msg }}</div>
</template>
<script setup>
const msg = 'Hello'
</script>

SFC advantages:


5. Component Registration

JS
// main.js
const { createApp } = Vue
import App from './App.vue'
import ProductCard from './components/ProductCard.vue'

const app = createApp(App)

// Global registration: every component can use <ProductCard />
app.component('ProductCard', ProductCard)

app.mount('#app')
VUE
<!-- HomeView.vue -->
<script setup>
// 1. Import
import ProductCard from '@/components/ProductCard.vue'

// 2. Use it in the template (no registration needed, it is available automatically)
</script>

<template>
  <ProductCard :product="product" />
</template>

(3) Comparing the Two

Dimension Global registration Local registration
Scope The whole application The current component
Code location main.js Inside the component's <script setup>
Tree-shaking ❌ Not supported ✅ Supported
Type hints Weak Strong (IDE autocomplete)
Recommendation ⭐⭐ For plugins ⭐⭐⭐⭐⭐ For business code

▶ Example: Global Registration vs Local Registration

▶ Try it Yourself

Output:

TEXT
A single blue button labeled Locally Registered Button.
Mounting replaces the content of #app, so the three <my-button> tags written in the raw HTML body never render — only the template of the locally registered App component does.
Uncommenting app.component('MyButton', MyButton) would make the component available application-wide instead.
TEXT
[Locally Registered Button]   (blue #3b82f6, white text)

6. Component Naming Conventions

(1) 3 Naming Styles

Style Example Usage Recommendation
PascalCase ProductCard.vue JS imports / in templates ⭐⭐⭐⭐⭐
kebab-case product-card.vue File names / kebab-case templates ⭐⭐⭐
camelCase productCard.vue Not recommended ⭐

(2) Using Them in Templates

(3) Folder Structure

TEXT
src/
├── components/          # Shared components (used across pages)
│   ├── ProductCard.vue
│   ├── Button.vue
│   └── Header.vue
├── views/               # Page components (used by the router)
│   ├── HomeView.vue
│   ├── ProductListView.vue
│   └── DashboardView.vue
├── composables/         # Composables
│   ├── useAuth.ts
│   └── useFetch.ts
├── router/              # Router configuration
└── App.vue              # Root component

7. props and emit Basics

(1) props: Parent → Child

(2) emit: Child → Parent

(3) props vs emit Cheat Sheet

Direction API Purpose
Parent → Child defineProps() Pass data
Child → Parent defineEmits() Notify with events

▶ Example: props 5 Types + Validators

▶ Try it Yourself

Output:

TEXT
One bordered card with a heading Administrator - Alice and three lines: Age: 25 | Status: Online, Role: admin | Frameworks: Vue, React, Angular, Email: alice@example.com | Per page: 20.
All nine props pass validation, so the console stays silent;
a value like status: 'blocked' or an email without @ would trigger a Vue prop validation warning.
TEXT
Administrator - Alice
Age: 25 | Status: Online
Role: admin | Frameworks: Vue, React, Angular
Email: alice@example.com | Per page: 20

(1) 📊 5 Component Design Principles

Principle Description
Single responsibility 1 component does 1 thing
Reusable Abstract common UI (Button/Input/Modal)
Configurable props control behavior, slots control content
Composable Small components compose into large ones
Easy to test Independent components are easy to unit-test

(2) 📊 5 Common Mistakes

Mistake Symptom Fix
Single-word component names IDE error Use PascalCase: ProductCard.vue
Too much global registration Bigger bundle Local registration supports tree-shaking
Components that are too large Hard to maintain Split into small components
Mutating props directly Vue warning props are read-only, use emit
Forgetting to import a component Template shows "unknown component" Check the imports in <script setup>

8. Putting It Together: The ProductCard Component End to End

▶ Example: ProductCard Component (Multi-Component CDN Demo)

▶ Expand runnable example (65 lines)
▶ Try it Yourself

Output:

TEXT
A Featured Products heading followed by three cards.
The first two show Only 5 left (stock 5) and an active Add to Cart button;
the third card is dimmed by .out-of-stock and its button reads Out of Stock with disabled.
The footer line starts at Cart items: 0 and increases by one each time an enabled button is clicked.
TEXT
Featured Products
iPhone 15 Pro
$999
[Add to Cart]

MacBook Pro
$2499
Only 5 left
[Add to Cart]

Sold Out Item
$99
[Out of Stock]  (disabled, card dimmed)

Cart items: 0

❓ FAQ

Q When should I use global registration?
A Only in 2 cases: (1) plugin-style components (like Element Plus's <el-button>); (2) base components used by the whole app (Button/Icon). Business components should always be registered locally so tree-shaking can work.
Q Must an SFC have all 3 parts?
A <template> and <script> are required, <style> is optional. If a component contains only JS (for example it just wraps data), it can skip the template and use a render function.
Q How large should a component file be?
A Under 200 lines is recommended. Beyond 300 lines, consider splitting it. The simpler the component, the easier it is to maintain.
Q SFCs use the .vue extension — how do other tools recognize it?
A Vite / Webpack / Vue CLI all recognize the .vue extension by default. In VS Code install the "Vue - Official" extension.
Q How do I test a single component?
A With Vitest + Vue Test Utils (@vue/test-utils): mount(ProductCard, { props: { product: mockProduct } }). Phase 4.6 of this tutorial covers it in detail.
Q How do I use a component library (Element Plus)?
A npm install → register globally in main.js → use <el-button> directly in templates. See Phase 4.7 for details.
Q What is the difference between SFC and React JSX?
A SFC uses an HTML-like template (close to web standards), React uses JSX (HTML written in JS). SFC has a gentler learning curve; JSX is flexible but needs a build step. Vue 3 also supports JSX (@vitejs/plugin-vue-jsx), but SFC is the default recommendation.

📖 Summary


📝 Exercises

  1. Basic (difficulty ⭐) Write a Button component src/components/BaseButton.vue:

    • props: text (String), variant (String, 'primary'/'success'/'danger')
    • 3 variants mapped to 3 classes
    • emit a click event
    • Use 3 different variants in HomeView.vue
  2. Intermediate (difficulty ⭐⭐) Build a product list + card system:

    • ProductCard.vue: a single product card (props: product, emit: add-to-cart)
    • ProductList.vue: the list container (v-for + filtering)
    • App.vue: the root component, passing data + handling add-to-cart
    • 3 files, 3 components nested together
  3. Challenge (difficulty ⭐⭐⭐) Build a complete "user card" component system:

    1. Avatar.vue: avatar component (supports both url / initials modes)
    2. UserCard.vue: user card (uses Avatar)
    3. UserList.vue: user list (uses UserCard)
    4. App.vue: root component (data + interactions)
    5. 5 props (avatar/name/email/role/active)
    6. 3 emitted events (edit/delete/select)
    7. scoped style isolation
Web-Tutorial.com

Web-Tutorial Tech Team

A team of developers maintaining programming tutorials. Each tutorial is written and reviewed by developers with expertise in that field. We work to keep our content accurate and reliable — if you spot an issue, please let us know.

100%

🙏 帮我们做得更好

我们是刚上线的编程教程站,几个人的小团队,精力有限。页面虽经检查,难免还有疏漏——链接失效、排版错乱、内容有误、语言生硬……

如果您发现了,麻烦告诉我们,我们会在收到反馈后第一时间进行修复,再次感谢您的光临 🙏