Simple Multi Step Form Wizard with Validation in VueJS

multi step form wizard vuejs

As part of learning VueJS one of my initial project involved creating a multi-step form or a form wizard in Vue JS.

There are Vue packages available for this but I wanted to do implement it myself with simplest implementation. Also there are code snippets and articles available but none of them matched it to be as dynamic as I want my implementation to be and none of them handled the validation.

So here it is, In this article I write about the implementation details of multi-step form in vue js, along with Validation.

To start with Let’s start with how I want my dynamic template to be like.

<form-wizard>
<tab name="Step 1" info="Introduction" :selected="true">
<!-- Step 1 of Form Goes Here-->
</tab>
<tab name="Step 2" info="More Details" >
<!-- Step 2 of Form Goes Here-->
</tab>
<tab name="Step 3" info="Finishing Up" >
<!-- Step 3 of Form Goes Here-->
</tab>
</form-wizard>

Here form-wizard is our parent component and tab is child component. You should be able to add as many tab (steps) in your form.

Let’s go into the details of both component.

Form-Wizard Component (Parent Component)

<template>
    <div>
        <ul class="steps has-content-centered">
            <li class="steps-segment" v-for="tab in tabs" :class="{ 'is-active': tab.isActive }" v-bind:key="tab">
                <span class="steps-marker"></span>
                <div class="steps-content">
                    <p class="is-size-4">{{tab.name}}</p>
                    <p>{{tab.info}}</p>
                </div>
            </li>
        </ul>                    
        <div class="tab-details">
            <slot></slot>
        </div>
        <br/>
        <div class="field is-grouped">
            <div class="control" v-if="currentActive > 0">
                <button @click="previousTab()" class="button is-primary">Previous</button>
            </div>
            <div class="control" v-if="currentActive < totalTabs - 1">
                <button @click="nextTab()" class="button is-link">Next</button>
            </div>
            <div class="control" v-if="currentActive == totalTabs -1" >
                <button @click="submit()" class="button is-success">Submit</button>
            </div>
        </div>
                
    </div>
</template>


<script>

import Tab from './Tab.vue'

export default {
  name: 'form-wizard',
  components:{
      Tab
  },
  data(){
    return{
        tabs: [],
        currentActive: 0,
        totalTabs: 0,
        
    }
   },

    created(){
        this.tabs = this.$children;
        
    },

    mounted(){
        this.totalTabs = this.tabs.length;
    },

    methods:{

        previousTab(){
            this.currentActive--;
            this.tabs.forEach(tab => {
                tab.isActive = false;
            });
                this.tabs[this.currentActive].isActive = true;

        },

        nextTab(){
            //Validate input
            this.$root.$validator.validate('step'+(this.currentActive+ 1)+'.*').then(valid => {
                if (valid){
                    this.currentActive++;
                    this.tabs.forEach(tab => {
                        tab.isActive = false;
                    });
            
                    this.tabs[this.currentActive].isActive = true;
                }
            }); 

        },

        submit(){
            
            this.$root.$validator.validate('step'+this.totalTabs+'.*').then(valid => {
                if (valid){
                    alert("Everything passes ! Ready to Submit")
                }
            });
        }  
    }
}
</script>


<style>
</style>

Although this looks complex (As every strange code does), I will try to simplify the details for you.

template : I have define a basic template which consists of a bulma stepper to track the status of where we are in the form. div with class tab-details will get everything that we define inside our form-wizard component. And below that I have defined three buttons (previous, next and submit) for navigation and submitting the form.

data : data properties are declared to maintain status of currently Active tab and also to get to know total number of child components.

created: Once we have our parent component created, we fetch all the child components (tab) and store them in local array.

mounted : Once the whole component is rendered, we get the count of total child components. (This is to know when to show the submit button in the end)

methods : We have defined three methods

previousTab() -> This is triggered on the click of previous button, It makes the previous tab active and hides all other tabs.

nextTab() -> This is triggered on the click of next button, First it does validation via vee-validate package of the current tab and if that passes then It makes the next tab active and hides all other tabs.

submit() -> This is triggered on the click of submit button. First it does validation of all the child Forms and if it passes we are ready to submit our Form.

Tab Component (Child Component)

Tab component is supposed to have the form fields.  For my demo I have used bulma component for the form design.

Here is how a form field looks like

<div class="field">
    <label class="label">Name</label>
    <div class="control">
        <input class="input" name="fullname" type="text" placeholder="Text input"  v-model="registration.name" data-vv-scope="step1" v-validate="'required'">
        <p class="help is-danger" v-show="errors.has('step1.fullname')">
                {{ errors.first('step1.fullname') }}
        </p>
    </div>
</div>

Apart from the usual HTML, following are the details of vue attributes used in the template.

v-model : is used to bind the element to a property. Form properties are defined in the root vue instance.

data-vv-scope : this attribute is used to group form fields for validation. So when we click the next button on Step 1 of form only fields marked step1 will be validated.

v-validate: This attribute denotes the validation as per vee-validate rules.

Below is the tab component code


<template> 
    <div v-show="isActive"><slot></slot></div> 
</template> 

<script> 
export default { 
    name: 'tab', 
    props: { 
        name:{
            required: true
        }, 
        info:{}, 
        selected: { 
            default: false
        } 
    }, 
    data(){ 
        return{ 
            isActive: false, 
        } 
    }, 
    created(){ 
        this.isActive = this.selected ;
    }, 
} 
</script>

<style> 
</style>

template: We have defined a basic template that slots in the form details inside a div.

props : name, info and selected property are accepted from attributes.

That’s about the components. For reactivity you must define your form fields inside the root vue instance.

export default {
  name: 'app',
  components: {
    FormWizard, Tab
  },
  data(){
    return{
    registration:{
          name: '',
          email: '',
          about: '',
          gender: '',
          reference: '',
          terms: '',     
     }
    }
  }
}

There you go. Multi Step Vue Form Wizard is implemented.

Code:

https://github.com/tushargugnani/vue-simple-form-wizard

Working Demo:

https://tushargugnani.github.io/vue-simple-form-wizard/

Web Stuff Enthusiast.

Related Posts

2 comments On Simple Multi Step Form Wizard with Validation in VueJS

Leave a reply:

Your email address will not be published.

Site Footer