Components
Vue.js Development
Components
Components are the fundamental building blocks of Vue applications. A component encapsulates its own template, logic, and styles into a reusable unit that can be composed with other components to build complex user interfaces. Vue's Single-File Component (SFC) format uses .vue files that combine the template, script, and style sections into a single file, providing a clean and organized development experience. Components communicate with their parents through props (data flowing down) and events (data flowing up), creating a clear and predictable data flow architecture.
Single-File Components
A Vue Single-File Component has three optional sections: <template> for HTML, <script> for JavaScript logic, and <style> for CSS. The scoped attribute on the style tag limits CSS to the current component.
<!-- AlertBox.vue -->
<template>
<div class="alert" :class="`alert-${type}`">
<strong>{{ title }}</strong>
<p>{{ message }}</p>
<button v-if="dismissible" @click="$emit('dismiss')">Close</button>
</div>
</template>
<script>
export default {
name: "AlertBox",
props: {
title: { type: String, required: true },
message: { type: String, required: true },
type: {
type: String,
default: "info",
validator(value) {
return ["info", "success", "warning", "error"].includes(value);
},
},
dismissible: { type: Boolean, default: false },
},
emits: ["dismiss"],
};
</script>
<style scoped>
.alert { padding: 16px; border-radius: 8px; margin: 8px 0; }
.alert-info { background: #e3f2fd; color: #1565c0; }
.alert-success { background: #e8f5e9; color: #2e7d32; }
.alert-warning { background: #fff3e0; color: #e65100; }
.alert-error { background: #ffebee; color: #c62828; }
</style>
Props
Props are custom attributes that pass data from parent to child components. Vue supports type checking, default values, required flags, and custom validators for props.
<!-- UserCard.vue -->
<script>
export default {
props: {
// Basic type check
name: String,
// Multiple possible types
id: [String, Number],
// Required with type
email: { type: String, required: true },
// Default value
role: { type: String, default: "viewer" },
// Default value from factory function (for objects/arrays)
tags: {
type: Array,
default: () => [],
},
// Custom validator
status: {
type: String,
validator(value) {
return ["active", "inactive", "pending"].includes(value);
},
},
},
};
</script>
<!-- Parent usage -->
<template>
<UserCard
:id="1"
name="Alice"
email="alice@test.com"
role="admin"
status="active"
:tags="['developer', 'lead']"
/>
</template>
Slots
Slots allow parent components to inject content into child component templates. They enable flexible, composable component designs where the parent controls what is rendered inside the child's layout.
<!-- Card.vue -->
<template>
<div class="card">
<div class="card-header">
<slot name="header">Default Header</slot>
</div>
<div class="card-body">
<slot>Default content goes here.</slot>
</div>
<div class="card-footer">
<slot name="footer"></slot>
</div>
</div>
</template>
<!-- Parent usage with named slots -->
<template>
<Card>
<template #header>
<h2>Product Details</h2>
</template>
<!-- Default slot content -->
<p>This is the main content of the card.</p>
<p>It can contain any HTML or components.</p>
<template #footer>
<button @click="save">Save</button>
<button @click="cancel">Cancel</button>
</template>
</Card>
</template>
Component Registration
Components can be registered locally within a parent component or globally on the app instance. Local registration is preferred because it results in better tree-shaking and clearer dependency graphs.
<script>
// Local registration (preferred)
import AlertBox from "./AlertBox.vue";
import UserCard from "./UserCard.vue";
import Card from "./Card.vue";
export default {
components: {
AlertBox,
UserCard,
Card,
},
};
</script>
// Global registration (main.ts)
// import AlertBox from "./components/AlertBox.vue";
// app.component("AlertBox", AlertBox);
Tip: Usescopedstyles by default to prevent CSS leaking between components. When you need to style child components from a parent, use the:deep()combinator::deep(.child-class) { color: red; }.
Key Takeaways
- Single-File Components (
.vue) combine template, script, and style in one file. - Props pass data from parent to child with type checking, defaults, and validators.
- Slots let parents inject content into child component templates for flexible composition.
- Named slots use
#slotNamesyntax for targeting specific slot locations. - Prefer local component registration for better tree-shaking and clearer dependencies.