Vue Components

Learn how to create and use Vue components, the building blocks of Vue.js applications. Components help you organize your code into reusable, self-contained pieces.

What is a Vue Component?

A Vue component is a reusable piece of your user interface with its own HTML, CSS, and JavaScript. Think of components like LEGO bricks - you can combine them to build complex applications.

Creating Your First Component

Single File Components (SFC)

The most common way to create Vue components is using Single File Components with the .vue extension:

<template>
  <div class="greeting">
    <h2>{{ title }}</h2>
    <p>{{ message }}</p>
    <button @click="sayHello">Say Hello</button>
  </div>
</template>

<script>
export default {
  name: 'Greeting',
  data() {
    return {
      title: 'Welcome!',
      message: 'This is my first Vue component'
    }
  },
  methods: {
    sayHello() {
      alert('Hello from the component!')
    }
  }
}
</script>

<style scoped>
.greeting {
  padding: 20px;
  border: 1px solid #ddd;
  border-radius: 8px;
  background-color: #f9f9f9;
}

h2 {
  color: #42b883;
  margin-bottom: 10px;
}

button {
  background-color: #42b883;
  color: white;
  border: none;
  padding: 8px 16px;
  border-radius: 4px;
  cursor: pointer;
}

button:hover {
  background-color: #369870;
}
</style>

Component Structure

A Vue component has three main sections:

  • <template>: The HTML structure of your component
  • <script>: The JavaScript logic and data
  • <style scoped>: CSS styles that only apply to this component

Using Components

Importing Components

To use a component in another component, you need to import it:

<template>
  <div>
    <h1>My App</h1>
    <Greeting />
    <Greeting />
  </div>
</template>

<script>
import Greeting from './components/Greeting.vue'

export default {
  name: 'App',
  components: {
    Greeting
  }
}
</script>

Component Registration

You can register components locally (as shown above) or globally:

// main.js
import { createApp } from 'vue'
import Greeting from './components/Greeting.vue'

const app = createApp(App)

// Global registration
app.component('Greeting', Greeting)

app.mount('#app')

Props: Passing Data to Components

Props let you pass data from parent components to child components:

<!-- UserProfile.vue -->
<template>
  <div class="user-profile">
    <img :src="user.avatar" :alt="user.name" />
    <h3>{{ user.name }}</h3>
    <p>{{ user.email }}</p>
    <p>Member since: {{ joinDate }}</p>
  </div>
</template>

<script>
export default {
  name: 'UserProfile',
  props: {
    user: {
      type: Object,
      required: true
    },
    joinDate: {
      type: String,
      default: 'Unknown'
    }
  }
}
</script>

Using Props

<template>
  <div>
    <UserProfile 
      :user="currentUser" 
      :join-date="formattedDate" 
    />
  </div>
</template>

<script>
import UserProfile from './UserProfile.vue'

export default {
  components: {
    UserProfile
  },
  data() {
    return {
      currentUser: {
        name: 'John Doe',
        email: '[email protected]',
        avatar: 'https://example.com/avatar.jpg'
      },
      formattedDate: 'January 2024'
    }
  }
}
</script>

Events: Communicating from Child to Parent

Components can emit events to communicate with their parents:

<!-- Counter.vue -->
<template>
  <div class="counter">
    <p>Count: {{ count }}</p>
    <button @click="increment">+</button>
    <button @click="decrement">-</button>
  </div>
</template>

<script>
export default {
  name: 'Counter',
  data() {
    return {
      count: 0
    }
  },
  methods: {
    increment() {
      this.count++
      this.$emit('count-changed', this.count)
    },
    decrement() {
      this.count--
      this.$emit('count-changed', this.count)
    }
  }
}
</script>

Listening to Events

<template>
  <div>
    <Counter @count-changed="handleCountChange" />
    <p>Latest count: {{ latestCount }}</p>
  </div>
</template>

<script>
import Counter from './Counter.vue'

export default {
  components: {
    Counter
  },
  data() {
    return {
      latestCount: 0
    }
  },
  methods: {
    handleCountChange(newCount) {
      this.latestCount = newCount
    }
  }
}
</script>

Slots: Component Content Distribution

Slots let you pass content from a parent component into a child component:

<!-- Card.vue -->
<template>
  <div class="card">
    <div class="card-header">
      <slot name="header">
        <h3>Default Header</h3>
      </slot>
    </div>
    <div class="card-body">
      <slot></slot>
    </div>
    <div class="card-footer">
      <slot name="footer">
        <button>Default Action</button>
      </slot>
    </div>
  </div>
</template>

<style scoped>
.card {
  border: 1px solid #ddd;
  border-radius: 8px;
  overflow: hidden;
  margin: 10px;
}

.card-header {
  background-color: #f8f9fa;
  padding: 15px;
}

.card-body {
  padding: 20px;
}

.card-footer {
  background-color: #f8f9fa;
  padding: 15px;
}
</style>

Using Slots

<template>
  <div>
    <Card>
      <template #header>
        <h2>User Profile</h2>
      </template>
      
      <p>This is the main content of the card.</p>
      <p>You can put any HTML here.</p>
      
      <template #footer>
        <button @click="save">Save</button>
        <button @click="cancel">Cancel</button>
      </template>
    </Card>
  </div>
</template>

Best Practices

  1. Keep components small and focused - Each component should do one thing well
  2. Use descriptive names - Make it clear what each component does
  3. Validate props - Always validate props to catch errors early
  4. Use scoped styles - Prevent CSS conflicts between components
  5. Document your components - Explain what props and events your components accept

Next Steps

Now that you understand components, learn about reactive data and state management in Vue.js.

External Resources

Last updated on