Vue Tutorial menu

Vue Components, Props and Emits

Components let you split a Vue app into small, reusable pieces that each do one job.

Creating and Using a Component

Create a file src/components/CourseCard.vue:

Example

vue
<script setup>
const title = "Web Development";
</script>

<template>
  <div class="card">
    <h3>{{ title }}</h3>
  </div>
</template>

<style scoped>
.card {
  border: 1px solid #ddd;
  border-radius: 8px;
  padding: 12px;
}
</style>

To use it in App.vue, import it in <script setup> and write it as a tag:

Example

vue
<script setup>
import CourseCard from "./components/CourseCard.vue";
</script>

<template>
  <h1>Our Courses</h1>
  <CourseCard />
  <CourseCard />
</template>

With <script setup>, an imported component is ready to use. No extra registration is needed.

Component names use PascalCase, like CourseCard, and are usually made of two or more words.

Props: Passing Data Down

Props let the parent send data into a child. Declare them with defineProps:

Example

vue
<!-- CourseCard.vue -->
<script setup>
const props = defineProps({
  title: String,
  months: Number,
  isNew: { type: Boolean, default: false },
});
</script>

<template>
  <div class="card">
    <h3>{{ title }} <span v-if="isNew">(New)</span></h3>
    <p>Duration: {{ months }} months</p>
  </div>
</template>

The parent passes them like attributes. Use : for anything that is not a plain string:

Example

vue
<CourseCard title="Web Development" :months="6" />
<CourseCard title="Artificial Intelligence" :months="4" :is-new="true" />
Output
Web Development
Duration: 6 months
Artificial Intelligence (New)
Duration: 4 months

In the template you can write isNew or is-new; Vue matches both. In the script, read a prop as props.title.

Props are read-only in the child. If a child needs to change something, it should ask the parent with an event.

Emits: Sending Events Up

A child tells its parent that something happened by emitting an event. Declare events with defineEmits:

Example

vue
<!-- EnrolButton.vue -->
<script setup>
const props = defineProps({ course: String });
const emit = defineEmits(["enrol"]);
</script>

<template>
  <button @click="emit('enrol', props.course)">Enrol in {{ course }}</button>
</template>

The parent listens with @:

Example

vue
<script setup>
import { ref } from "vue";
import EnrolButton from "./components/EnrolButton.vue";

const chosen = ref("");
</script>

<template>
  <EnrolButton course="Graphic Designing" @enrol="(name) => (chosen = name)" />
  <p v-if="chosen">You chose {{ chosen }}.</p>
</template>
Output
(after click)
You chose Graphic Designing.
DirectionTool
Parent to childProps (defineProps)
Child to parentEvents (defineEmits)

v-model on a Component

Vue 3.4 and later have defineModel, which makes v-model work on your own components:

Example

vue
<!-- QuantityInput.vue -->
<script setup>
const quantity = defineModel({ type: Number, default: 1 });
</script>

<template>
  <button @click="quantity--">-</button>
  {{ quantity }}
  <button @click="quantity++">+</button>
</template>

Example

vue
<QuantityInput v-model="plates" />

Slots: Passing Content

A <slot> is a place where the parent can put its own content:

Example

vue
<!-- InfoBox.vue -->
<template>
  <div class="box">
    <slot>Default text if nothing is given</slot>
  </div>
</template>

Example

vue
<InfoBox>
  <strong>Note:</strong> Classes are closed on Sunday.
</InfoBox>
Output
Note: Classes are closed on Sunday.

Rendering Components in a List

Example

vue
<CourseCard
  v-for="c in courses"
  :key="c.id"
  :title="c.name"
  :months="c.months"
/>

What Comes Next

When your app grows, you will want more tools:

  • Vue Router for multiple pages, like /courses and /contact
  • Pinia to share state between many components
  • Nuxt as a full framework with server rendering

Exercise

Exercise

How does a child component send information back to its parent in Vue?

Learn Vue with a teacher

Join the Full Stack Development course at Workownix, online or in Orangi Town, Karachi, and get a certificate.

See the course Ask on WhatsApp