Components

Back

Loading concept...

🧩 Vue.js Component Basics: Building Blocks of Your App

Imagine you’re building with LEGO blocks. Each block is a small piece, but together they create amazing things!


🎯 What Are Components?

Think of components like recipe cards in a kitchen. Each card tells you how to make one dish. You can use the same recipe card again and again to make the same dish multiple times!

In Vue.js:

  • A component = a reusable piece of your app
  • It has its own look (HTML) and behavior (JavaScript)
  • You build big apps by combining small components
graph TD A["🏠 Your App"] --> B["πŸ“¦ Header Component"] A --> C["πŸ“¦ Sidebar Component"] A --> D["πŸ“¦ Main Content"] D --> E["πŸ“¦ Card Component"] D --> F["πŸ“¦ Card Component"] D --> G["πŸ“¦ Card Component"]

πŸ“ Defining a Component

There are two ways to write a component. Think of it like writing a letter - you can use a quick note or a formal letter format!

Way 1: Single-File Component (SFC)

This is the formal letter - everything organized in one .vue file:

<script setup>
import { ref } from 'vue'
const count = ref(0)
</script>

<template>
  <button @click="count++">
    Clicked {{ count }} times
  </button>
</template>

Way 2: Plain JavaScript Object

This is the quick note - good for simple cases:

export default {
  data() {
    return { count: 0 }
  },
  template: `
    <button @click="count++">
      Clicked {{ count }} times
    </button>
  `
}

πŸ’‘ Pro Tip: Most developers use Single-File Components because they’re easier to organize!


🏷️ Component Registration

Before using a component, Vue needs to know it exists. It’s like introducing yourself before joining a party!

There are two types of registration:

Type Where it works Best for
Global Everywhere in your app Components you use often
Local Only where you import it Most components

🌍 Global Registration

Global = Available Everywhere

Imagine you have a favorite toy that you want in every room of your house. You tell your parents once, and now it’s available everywhere!

import { createApp } from 'vue'
import MyButton from './MyButton.vue'

const app = createApp({})

// Register globally - now use
// <MyButton> anywhere!
app.component('MyButton', MyButton)

⚠️ The Catch

Global components have two problems:

  1. πŸŽ’ Extra weight - They’re always loaded, even if unused
  2. πŸ” Hard to track - You can’t see where they come from
graph TD A["🌍 Global Component"] --> B["Page 1 βœ…"] A --> C["Page 2 βœ…"] A --> D["Page 3 βœ…"] A --> E["Page 4 - Not using it πŸ˜•"] style E fill:#ffcccc

πŸ“ Local Registration

Local = Available Only Where You Import

This is like borrowing a book from the library. You bring it to your room, use it, and it only exists in that room!

<script setup>
import ButtonCounter from './ButtonCounter.vue'
</script>

<template>
  <ButtonCounter />
</template>

That’s it! With <script setup>, imported components are automatically available. No extra steps!

Without <script setup>

If you use the Options API, you need one more step:

import ButtonCounter from './ButtonCounter.vue'

export default {
  components: {
    ButtonCounter  // Register here
  }
}

βœ… Why Local is Better:

  • Only loads when needed (faster app!)
  • Easy to see where components come from
  • Better for tree-shaking (removing unused code)

πŸ“› Component Naming

Names matter! Vue gives you two ways to name components:

PascalCase (Recommended)

<template>
  <MyComponent />
  <AnotherWidget />
</template>

kebab-case

<template>
  <my-component></my-component>
  <another-widget></another-widget>
</template>

🎯 The Rule:

  • In JavaScript: Always use PascalCase
  • In Templates: Use PascalCase OR kebab-case

Vue automatically converts between them:

  • MyComponent β†’ <my-component>
  • ButtonCounter β†’ <button-counter>

Why PascalCase Wins πŸ†

<!-- Easy to spot Vue components! -->
<template>
  <MyButton>Click me</MyButton>
  <button>Native HTML</button>
</template>

PascalCase makes Vue components stand out from regular HTML elements!


🧱 Fragment Support

Fragments = Multiple Root Elements

In Vue 2, every component needed ONE wrapper element. It was like forcing every gift into ONE box!

<!-- Vue 2: This was REQUIRED 😀 -->
<template>
  <div>
    <h1>Title</h1>
    <p>Content</p>
  </div>
</template>

Vue 3 changed everything! Now you can have multiple elements at the root:

<!-- Vue 3: No wrapper needed! πŸŽ‰ -->
<template>
  <h1>Title</h1>
  <p>Content</p>
</template>

How Attributes Work with Fragments

When a component has one root, attributes pass through automatically:

<!-- Parent uses component with class -->
<MyComponent class="fancy" />

<!-- Single root: class goes here -->
<template>
  <div>I get the "fancy" class!</div>
</template>

With multiple roots, YOU choose where attributes go:

<template>
  <h1>Title</h1>
  <p v-bind="$attrs">I get the attributes!</p>
</template>

πŸ”„ Dynamic Components

Dynamic = Changes Based on Conditions

Imagine a TV that can switch channels. The screen stays the same, but the content changes!

Vue uses the special <component> element with :is to swap components:

<script setup>
import TabHome from './TabHome.vue'
import TabPosts from './TabPosts.vue'
import TabArchive from './TabArchive.vue'
import { ref } from 'vue'

const currentTab = ref('TabHome')

const tabs = {
  TabHome,
  TabPosts,
  TabArchive
}
</script>

<template>
  <button
    v-for="(_, name) in tabs"
    @click="currentTab = name"
  >
    {{ name }}
  </button>

  <!-- Magic happens here! -->
  <component :is="tabs[currentTab]" />
</template>
graph LR A["Click Tab"] --> B{Which Tab?} B -->|Home| C["Show TabHome"] B -->|Posts| D["Show TabPosts"] B -->|Archive| E["Show TabArchive"]

🎭 The is Attribute

The is attribute is like a magic wand that transforms elements!

Use Case 1: Dynamic Components

<component :is="currentComponent" />

Use Case 2: Working with HTML Rules

Some HTML elements have strict rules about what can go inside them:

<!-- ❌ WRONG: <tr> can't be direct child -->
<table>
  <my-row></my-row>
</table>

<!-- βœ… RIGHT: Use is with vue: prefix -->
<table>
  <tr is="vue:my-row"></tr>
</table>

This works for:

  • <table> β†’ needs <tr>, <td>
  • <ul>, <ol> β†’ needs <li>
  • <select> β†’ needs <option>

The vue: Prefix

When using is in DOM templates, add the vue: prefix:

<tr is="vue:my-component"></tr>

This tells Vue: β€œHey, this should be a Vue component, not just an HTML attribute!”


🎁 Putting It All Together

Let’s see everything working together in one example:

<script setup>
import { ref, shallowRef } from 'vue'

// Local registration (just import!)
import HomeTab from './HomeTab.vue'
import ProfileTab from './ProfileTab.vue'
import SettingsTab from './SettingsTab.vue'

const tabs = { HomeTab, ProfileTab, SettingsTab }
const activeTab = shallowRef(HomeTab)
</script>

<template>
  <!-- Fragment: Multiple root elements -->
  <nav>
    <button
      v-for="(comp, name) in tabs"
      :key="name"
      @click="activeTab = comp"
    >
      {{ name.replace('Tab', '') }}
    </button>
  </nav>

  <!-- Dynamic component with is -->
  <component :is="activeTab" />
</template>

πŸš€ Quick Summary

Concept What It Does
Defining Create reusable UI pieces with SFC or JS objects
Global Registration Use component anywhere (but avoid overuse)
Local Registration Import where needed (recommended!)
Naming PascalCase in JS, either case in templates
Fragments Multiple root elements (Vue 3 only)
Dynamic Components Swap components with <component :is>
is Attribute Transform elements, bypass HTML restrictions

πŸŽ‰ You Did It!

You now understand Vue components like a pro! Remember:

🧩 Components are like LEGO blocks - small, reusable, and powerful when combined!

Start small, build up, and soon you’ll be creating amazing apps with components!

Happy coding! πŸš€

Loading story...

Story - Premium Content

Please sign in to view this story and start learning.

Upgrade to Premium to unlock full access to all stories.

Stay Tuned!

Story is coming soon.

Story Preview

Story - Premium Content

Please sign in to view this concept and start learning.

Upgrade to Premium to unlock full access to all content.