DEV Community

Cover image for 4 different ways to create Vue Components
Lilo
Lilo

Posted on

4 different ways to create Vue Components

Did you know that there are several ways to create Vue Components?
Here we'll discuss 4 of them.

TL;DR

I've created a CodeSandbox project to demonstrate those 4 ways.
If you'd like to self-explore, go ahead and click here.
If you want the full picture, keep reading.

The full story

For demonstration purposes, I came up with this simple task that is required from each component that we'll create:

Component Requirements

  1. Get a list of string items (in the props).
  2. Display a button for each item.
    • Each button should have lightsteelblue background.
    • The text of each button should be the string of that item.
    • upon clicking a button, the related item is considered selected.
  3. Display a status string inside a <p> element.
    • at first the status should be Please select your favorite.
    • when an item is selected the status will change to reflect that selection. For example: if Picard is selected, the status should be: You selected Picard (yeah, I'm a Trekkie)

I then went ahead and created 4 components:

The 4 types of stateful* components

  1. SFC (Single File Component)
  2. Component with a template
  3. Component with a render function
  4. Component with a render function and JSX syntax

*There's one more type, a functional component, but it is stateless and therefore cannot help us in this imaginary task

So, let's check out the implementations...

Implementations

1. SFC (Single File Component)

This is the most common one and should be used as default.
The .vue file is actually an html file that is being pre-processed by the Vue CLI to allow for special features in the template and in the style tag (e.g. scss and scoped styles)

<template>
    <div>
        <button v-for="(item, index) in items" :key="index" @click="onItemSelected(item)">{{item}}</button>
        <p v-if="selectedItem">You selected {{selectedItem}}</p>
        <p v-else >Please select your favorite</p>
    </div>
</template>

<script>
    export default {
        name: "ListItemsSfc",
        props: ['items'],
        data() {
            return {
                selectedItem: null
            }
        },
        methods: {
            onItemSelected(item) {
                this.selectedItem = item;
            }
        }
    }
</script>

<style scoped>
    button {
        background: lightsteelblue;
    }
</style>

2. Component with a template

This is pretty similar to SFC only you don't get the scoped styling and the syntax highlighting (since the template is actually a string)

import Vue from 'vue/dist/vue.js'; // <-- important for template components to work

Vue.component('ListItemsTemplate', {
    props: ['items'],
    data() {
        return {
            selectedItem: null
        }
    },
    methods: {
        onItemSelected(item) {
            this.selectedItem = item;
        }
    },
    template: `
                <div>
                    <button style="background: lightsteelblue" v-for="(item, index) in items" :key="index" @click="onItemSelected(item)">{{item}}</button>
                    <p v-if="selectedItem">You selected {{selectedItem}}</p>
                    <p v-else >Please select your favorite</p>
                </div>

                `
});

3. Component with a render function

Allows for a more dynamic creation of the component's template.
The render function accepts a createElement function that is used for rendering a single html element (here shortened as ce).
The createElement function receives a tag name, an optional data object and an optional content that can be text or additional html child elements, also created with this function.

import Vue from 'vue/dist/vue.js'; // <-- important for template components to work

Vue.component('ListItemsRender', {
    props: ['items'],
    data() {
        return {
            selectedItem: null
        }
    },
    methods: {
        onItemSelected(item) {
            this.selectedItem = item;
        }
    },
    render(ce) {
        let getButtonData = (item) => {
            return {
                style: { background: 'lightsteelblue' },
                on: { click: () => this.onItemSelected(item) }
            }
        };
        let buttons = this.items.map(item => ce('button', getButtonData(item), item));
        let statusText = this.selectedItem ? `You selected ${this.selectedItem}` :
            'Please select your favorite';

        return ce('div', [...buttons, ce('p',statusText)]);
    }
});

4. Component with a render function and JSX syntax

It makes writing complex templates easier.

import Vue from 'vue/dist/vue.js'; // <-- important for template components to work

Vue.component('ListItemsJsx', {
    props: ['items'],
    data() {
        return {
            selectedItem: null
        }
    },
    methods: {
        onItemSelected(item) {
            this.selectedItem = item;
        }
    },
    render(h){

        let buttons = this.items.map(item => <button onClick={() => this.onItemSelected(item)} style="background:lightsteelblue">{item}</button>);
        let statusText = this.selectedItem ? `You selected ${this.selectedItem}` :
            'Please select your favorite';

        return (
            <div>
                {buttons}
                <p>{statusText}</p>
            </div>
        );
    }
});

And here's the final result, hosted on CodeSandbox. You can open the project and play with the components to test them out.

The final result

Let me know in the comments in case you have any general questions or any questions related specifically to one of the alternatives presented here.

Coded with love,
Lilo

Top comments (5)

Collapse
 
samarkk profile image
The Learner

thanks - very useful, to the point, compact article clarifying varied ways of vue component creation. helped me

Collapse
 
rolandcsibrei profile image
Roland Csibrei

Thanks for sharing.

Collapse
 
starvsion profile image
Junhai

You can also do it in a HTML file without compiling any js

Collapse
 
lilotop profile image
Lilo

Of course. You can also do it in React and in Angular. However, this post is about Vue. The example was simple on purpose, for illustration.

Collapse
 
rolandcsibrei profile image
Roland Csibrei

This is the most dumb comment ever...