Vue.js 3 Components Tutorial

In this Vue tutorial we learn about single file components (.vue files) and the root App component.

We cover how they're rendered, the steps to create a component and nesting them.

Lesson Project

If you want to follow along with the examples in this lesson, you will need an app generated by the Vue CLI . If you already have one from the previous lesson, you can use it instead.

Vue's component architecture

Vue’s architecture is based on the idea of coupled components. A component is a smaller piece of the UI/app that performs a single task. We combine these components into views (pages) that eventually forms the full application.

As an example, let’s consider a simple Task List app.

We have a component that’s responsible for adding a new task, and one that’s responsible for displaying all the tasks in our list.


Component Architecture

Each component is a self-contained unit of HTML, CSS and Javascript (or TypeScript). Everything it needs to function is contained in the component’s file.

A component can also be made up of multiple other components. For example, an active task can be its own component, as well as a completed task.


Nested Component Architecture

There are many ways components can communicate with each other and share data, like props and events , or get data from an external resource like Firebase .

Single File Components (SFCs - .vue files)

In the First App lesson , we learned that components use the .vue extension. The .vue extension is a custom file format that Vue understands, it knows that it’s a component and what to look for inside.

We also learned that a .vue file typically consists of three types of language blocks.

  • The <template></template> block is the HTML markup of the UI. It defines the structure.
  • The <script></script> block is where we maintain the data and logic for the template.
  • The <style></style> block contains the styling for the markup in the template block.
Example: component structure
<template>
  <!-- HTML markup here -->
</template>

<script>
  // component functionality here
</script>

<style>
  /* markup styling here */
</style>

The template and the style blocks are known as the View, and the script block is known as the Logic. All the blocks together is known as Template Syntax.

Components are typically stored in a separate folder like /src/components/ . The only exception is the root App component (the App.vue file) which is stored in the /src/ folder.

The root App component (App.vue)

The root App component wraps all other components in our application and exists as the App.vue file in the /src/ folder of our projects.

Up until now, we’ve been using the root App component to explain Vue’s fundamental concepts. But typically, it’s only used to register other components and display them on certain conditions, or when routing.

Component rendering

Components are part of the Vue framework, a browser can’t understand them or process their contents.

When we run the development server, or build the application for production, Webpack and the Vue loader will parse the code and extract the three blocks. It will then pipe them through other loaders like Babel or SCSS if necessary, and assemble them into the HTML, CSS and Javascript that a browser can understand.

Vue takes care of this whole process, so we don’t have to worry about it.

How to create a component

As mentioned before, a component is just a .vue file that contains up to three language blocks with our markup, logic and styling.

Go ahead and create a new file in the /src/components/ directory called GreetingMessage.vue . The file name can use PascalCase, camelCase, kebab-case or snake_case but it’s convention to use PascalCase.

Example: project
project-folder/
├── src/
|   ├── components/
|   |   ├── GreetingMessage.vue
|   └── App.vue

Inside the new component, add a heading with some static text.

Example: src/components/GreetingMessage.vue
<template>
  <h1>Hello from a component</h1>
</template>

At the moment, the message won’t be rendered in the browser because this component is not connected with the rest of the application.

To connect it, we follow a simple 3 step process.

  1. Step 1: Import the component into another component that is connected. If there aren’t any, we can import it into the root App component.
  2. Step 2: Register the component in the config object.
  3. Step 3: Use the component in the template by adding its custom tag.

Because we don’t have any other component that’s already connected, we’ll use the root App component.

Step 1: Import the component

To import a component, we use the import..from statement at the top of the script block.

Syntax: import
<script>
import ComponentName from './path-to/ComponentName'

export default { }
</script>

The Vue CLI uses Webpack as its bundler. Webpack understands what a .vue file is, so we don’t have to specify the extension in our import.

For the path we use standard path navigation.

Example: paths
'./'      // same directory
'../'     // up one directory
'../../'  // up two directories etc.

As an example, let’s import our new GreetingMessage component in the App.vue file’s script block.

Example: src/App.vue
<template>
  <div></div>
</template>

<script>
import GreetingMessage from './components/GreetingMessage'
</script>

Step 2: Register the component

To register imported components, we specify them in the components option in the config object of the component we’re importing into.

Syntax: register
<script>
import ComponentName from './path-to/ComponentName'

export default {
  components: {
    ComponentName: 'ComponentName'
  }
}
</script>

We can use the ES6 shorthand syntax when the object’s key and value is the same.

Syntax: register
<script>
import ComponentName from './path-to/ComponentName'

export default {
  components: {
    ComponentName
  }
}
</script>

As an example, we’ll register the GreetingMessage component we imported.

Example: src/App.vue
<template>
  <div></div>
</template>

<script>
import GreetingMessage from './components/GreetingMessage'

export default {
  components: { GreetingMessage }
}
</script>

Step 3: Use the component

Now that Vue knows about the component, we can use it where we need inside the template block by specifying it as a custom HTML tag.

The custom tag is the name of the component. If it will not contain anything inside it, we can specify it as a self-closing tag.

Syntax: use
<template>
  <ComponentName></ComponentName>
  <!-- or -->
  <ComponentName />
</template>

<script>
import ComponentName from './path-to/ComponentName'

export default {
  components: {
    ComponentName,
  }
}
</script>

We can use either PascalCase or kebab-case when we create an instance of a component.

However, PascalCase tags don’t comply with the W3C rules for custom tag names so it’s recommended to use kebab-case only.

When we use kebab-case, it’s only for the tag name. We don’t have to change the component’s file name to match, Vue will automatically convert it.

Syntax: W3C recommended tags
<template>
  <component-name></component-name>
  <!-- or -->
  <component-name />
</template>

<script>
// PascalCase is fine outside the template
import ComponentName from './path-to/ComponentName'

export default {
  components: {
    ComponentName,
  }
}
</script>

For our example, let’s replace the div in our template with the GreetingMessage component.

Example: src/App.vue
<template>
  <greeting-message />
</template>

<script>
import GreetingMessage from './components/GreetingMessage'

export default {
  components: { GreetingMessage }
}
</script>

That’s it. If we run the example in the browser, we should see the message in the heading.

Nested components

As we mentioned earlier, components can be made up of other components. We follow the same process as before but instead of importing it into the root App component, we’ll import it into the GreetingMessage component.

For some practice, try to do it on your own. If you get stuck, just look at our examples below.

We’ll create the following 3 components in /src/components/ .

  • ComponentA.vue
  • ComponentB.vue
  • ComponentC.vue

To keep it simple, each component will have a paragraph with its name and some styling applied.

Example: src/components/ComponentA.vue
<template>
  <p>Component A</p>
</template>

<style scoped>
p { color:white;background:blue }
</style>

Don’t worry about the CSS right now, we cover styling in the Component Styles lesson .

Example: src/components/ComponentB.vue
<template>
  <p>Component B</p>
</template>

<style scoped>
p { color:white;background:red }
</style>
Example: src/components/ComponentC.vue
<template>
  <p>Component C</p>
</template>

<style scoped>
p { color:white;background:black }
</style>

We’ll import, register and use the new components in GreetingMessage.vue .

Example: src/components/GreetingMessage.vue
<template>
  <h1>Hello from GreetingMessage</h1>
  <hr>

  <component-a />
  <component-b />
  <component-c />
</template>

<script>
import ComponentA from './ComponentA'
import ComponentB from './ComponentB'
import ComponentC from './ComponentC'

export default {
  components: {
    ComponentA,
    ComponentB,
    ComponentC
  }
}
</script>

If we run the example in the browser, we should see the big heading, followed by the nested components in their colors.