The 2023 guide to Vue components

Ryan Lucas
Ryan Lucas
Head of Design @ Retool

May 13, 2022

This post was written with help from Ikeh Akinyemi.

Vue components are usually suffixed with the .vue extension. They're custom elements that are created using JavaScript objects, an HTML-like syntax, and sometimes a style block to style the component. Components can receive data from other components, known as props, which can be imported and used by multiple components.

The examples outlined in this post require Vue3.

Here's an example of a typical Vue component:

1// HTML-like template
3    <h1> Hello World! </h1>
6// JavaScript Object
8  export default {
9    name: 'Greet'
10  };
13// style
15    h1 {
16       color: black;
17    }

Vue provides a compiler that processes the content in <template> and returns a render function, which in turn returns a virtual DOM node—Vue's DOM, which determines what UI will be updated and rendered in your browser's DOM.

In this guide, you'll learn about different types of components in Vue, how they work, and the use cases for each of them.

Class components

Vue allows you to create a component with class-like syntax using a built-in library called vue-class-component. Many devs use vue-property-decorator, which you can learn more about here, because it comes with special features called decorators—a kind of declaration that can be attached to a class, method, accessor property, or parameter, usually in the form @expression. Class-like syntax promotes object-oriented programming (OOP) concepts such as inheritance, where you can inherit certain properties, values, or methods from another class or object using the extends keyword.

A good time to use class components is when you have a complex component, such as a modal or a form. Using class components will help organize your code into separate methods and properties, which improves readability.

How it works

To use the Vue class component, you have to install it:

1    $ npm install --save  vue-class-component

Here’s a typical sample code snippet for class components in Vue:

2  <div>
3    <h1> {{ msg }} </h1>
4    <button @click=“clearMessage”>Greet</button>
5  </div>
9    import { Component, Vue } from 'vue-class-component';
11    // Define the component using class-like syntax
12    @Component
13    export default class Greet extends Vue {
14      // component property
15      msg = ‘Hello World’
17      // component methods
18      clearMessage() {
19          this.msg = ‘’
20      }
22      sayHello() {
23          this.msg = ‘Hello World’
24      }
25    }

The template tag is used to specify the HTML-like syntax that maps to the DOM. Its data can be manipulated and set using methods and properties instantiated in the script tag. The @Component decorator makes your class a Vue component, while the next line defines the name of your component: Greet. This component inherits Vue properties and methods—for example, the mounted() method—and then exports them so other components can make use of them.

The Greet component can then be imported and used as follows:

1import Greet from './Greet.vue'
3    <Greet />

Dynamic components

Dynamic components allow you to switch between components at run time. Instead of using unique components separately, you can use a dynamic component to render a component based on certain conditions. It can replace conditional directives like v-if, v-else, and v-else-if with the v-bind:is directive which can also be written as :is, like so:

1<component :is="comp" />

Dynamic components can make your code much more reusable. They can also enhance speed, as they reduce page loads by rendering components dynamically rather than routing to the individual components.

Some sample use cases for dynamic components are:

  • navigating between tab components
  • rendering different contents on the page based on a user's login status
  • rendering different pop-ups dynamically

How it works

A dynamic component accepts a component by passing in the name of the component as the parameter, or in some cases, as the options object of the component. First, you have to import the components to be used dynamically:

1import Write from './Write.vue'
2import Preview from './Preview.vue'

Next, create a variable to represent the current component, which will be rendered by default and then dynamically later on based on user actions. This variable can be created as follows:

1export default {
2    components: {
3        Write,
4        Preview
5    }
6    data(){
7        return {
8            content: "Write" // default component to be rendered
9        }
10    }

And finally, we can add the components to our template:

2    <button @click='content = "Write"'> Write content here... </button> <!-- set content to `Write` component –> 
3    <button @click='content = "Preview"'> Preview content </button> <!-- set content to `Preview` component –>
4    <BlogPost :is='content' /> <!-- dynamic component which will render based on what button is clicked –>

Single-file components

A single-file component (commonly referred to as SFC) comprises of three blocks:

  • The <template></template> block, which is like the HTML of the UI.
  • The <script></script> block, where the logic and functionality of the application is processed.
  • The <style></style> block, which is responsible for styling the UI.

It is solely responsible for its layout/structure, logic, and style. This is what a typical single-file component looks like:

2  <p class="greeting">{{ greet }}</p>
6  export default {
7    data() {
8      return {
9        greet: 'Hello World!'
10      }
11    }
12  }
15<style scoped> // the `scoped` attribute applies this style ONLY to this component
16.greeting {
17  color: green;
18  font-family: sans-serif;

Some of the benefits of using single-file components are that it's constructed using familiar HTML, CSS, and JavaScript syntax, and that it encapsulates all concerns (structure, logic, and style) of an element in one component. It can also receive a scope attribute, such as <style scoped>, to its styling tag to restrict styles to a particular component.

Use cases for single-file components include:

  • creating single-page applications
  • creating static pages

How it works

The <template> block allows you to bind the rendered DOM to your specified Vue instance's data (usually in the <script> block), which then gets compiled into the virtual DOM. During development, the <style> block is injected into the browser as actual <style> tags to simplify hot updates.

The single-file component is usually pre-compiled by a Vue library called @vue/compiler-sfc into standard JavaScript and CSS.

Functional component

Functional components in Vue are components with no state, no lifecycle methods, and no instances, which means you cannot use the this keyword in them. Since they don't maintain their own state, they're not reactive. They can take in props and render a UI based on the received props, but they can't know when the data has changed. It's important to note that they are different from a render function, but can contain render functions in them.

Here's what a functional component template looks like:

1<template functional> <!-- note the functional keyword –>
2  <h1> {{props.sample}}</h1> <!-- accepts a prop called "sample">
6  export default {
7    props: {
8      sample: String
9    }
10  }

Since functional components have no state or reactivity, they're very fast, and because of their relative simplicity, they're easy to write and debug compared to dynamic components.

Use cases for functional components include:

  • presentational UIs where state or reactivity is not required
  • looping (using the v-for directive) and rendering list items

How it works

The functional component works just like the single-file component, only in this case, it has no state or instance, and includes a functional keyword in its <template> tag, which is what tells Vue that it is a functional component.

Table component

Table components, as the name implies, are components that allow you to render data in tabular form. In Vue, most developers use libraries like Bootstrap to render table components. To learn more about this, you can look at the BootstrapVue documentation.

Here's what a typical code snippet of a table component looks like:

2  <div>
3    <table>
4      <thead>
5        <tr>
6          <th v-for="(header, index) in headers" :key="index"> // loop through headers and render 'First Name', 'Last Name'
7            {{ header }}
8          </th>
9        </tr>
10      </thead>
11      <tbody>
12          <!--accept dataObject prop from parent component with sample data like so:
13           dataObject = [
14            { firstName: "Ikeh", lastName: "Akinyemi" },
15            { firstName: "Jeremiah", lastName: "Egbe" },
16            { firstName: "Chidi", lastName: "Ikeoha" },
17          ] -->
18        <tr v-for="(data, index) in dataObject" :key="index + 'x'">
19          <td>{{ data.firstName }}</td>
20          <td>{{ data.lastName }}</td>
21        </tr>
22      </tbody>
23    </table>
24  </div>
28export default {
29  name: "Table",
30  props: {
31    dataObject: Array,
32  },
33  computed: {
34    headers() {
35      const prop = ['First Name', 'Last Name']
36      return prop;
37    },
38  },
42  // Add "scoped" attribute to limit CSS to this component only
43  <style scoped>
44    table {
45      border-collapse: collapse;
46    }
47    tr, th {
48      background: white;
49    }
50    tr:nth-child(odd) {
51      background: #ccc;
52    }
53  </style>

Table components are useful because they help you clearly structure comparable or statistical data.

Some use cases for table components are:

  • rendering statistical data
  • illustrating differences between options, such as listing pricing and subscription options for an online product

How it works

Table components usually have a header, which is denoted using <thead>, and a table body. The body holds table rows and columns, which are represented using <tr> and <td> tags. This component can accept props and compute data to manipulate data that it renders. It can work with state, or work as functional components do, and it simply renders nonreactive tabular data.

Helpful? Have feedback? Tell us on Twitter.

And if you are building an internal tool, a personal app, or prototyping something cool, consider Retool's component library. You'll have over 90 components (example) to build polished and performant apps, with countless configuration options.


Ryan Lucas
Ryan Lucas
Head of Design @ Retool
May 13, 2022