JSFiddle - React, Tailwind, and code Playground

by CristiJ

HTML

<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css">
<script src="https://vuejs.org/js/vue.min.js"></script>
<link rel="stylesheet" href="https://rawgit.com/lykmapipo/themify-icons/master/css/themify-icons.css">
<link rel="stylesheet" href="https://rawgit.com/cristijora/vue-form-wizard/master/dist/vue-form-wizard.min.css">
<script src="https://rawgit.com/cristijora/vue-form-wizard/master/dist/vue-form-wizard.js"></script>
<script src="https://unpkg.com/vuelidate@0.5.0/dist/vuelidate.min.js"></script>
<script src="https://unpkg.com/vuelidate@0.5.0/dist/validators.min.js"></script>
<div id="app">
  <div>
    <form-wizard shape="square" color="#3498db">
      <tab-content title="Personal details" icon="ti-user" :before-change="()=>validateStep('step1')">
        <step1 ref="step1" @on-validate="mergePartialModels"></step1>
      </tab-content>
      <tab-content title="Additional Info" icon="ti-settings" :before-change="()=>validateStep('step2')">
        <step2 ref="step2" @on-validate="mergePartialModels"></step2>
      </tab-content>
      <tab-content title="Last step" icon="ti-check">
        Here is your final model:
       <pre>{{finalModel}}</pre>
      </tab-content>
    </form-wizard>
  </div>
</div>

JavaScript

Vue.use(window.vuelidate.default)
const {
  required,
  minLength,
  email
} = window.validators
Vue.use(VueFormWizard)

Vue.component('step1', {
  template: `<div>
          <div class="form-group" v-bind:class="{ 'has-error': $v.firstName.$error }">
            <label >First name</label>
            <input class="form-control" v-model.trim="firstName" @input="$v.firstName.$touch()">
             <span class="help-block" v-if="$v.firstName.$error && !$v.firstName.required">First name is required</span>
          </div>
          <div class="form-group" v-bind:class="{ 'has-error': $v.lastName.$error }">
            <label>Last name</label>
            <input class="form-control" v-model.trim="lastName" @input="$v.lastName.$touch()">
             <span class="help-block" v-if="$v.lastName.$error && !$v.lastName.required">Last name is required</span>
          </div>
          
          <div class="form-group" v-bind:class="{ 'has-error': $v.email.$error }">
            <label>Email</label>
            <input class="form-control" v-model.trim="email" @input="$v.email.$touch()">
            <span class="help-block" v-if="$v.email.$error && !$v.email.required">Email is required</span>
            <span class="help-block" v-if="$v.email.$error && !$v.email.email">This is not a valid email!</span>
          </div>
        </div>`,
  data() {
    return {
      firstName: '',
      lastName: '',
      email: ''
    }
  },
  validations: {
    firstName: {
      required
    },
    lastName: {
      required
    },
    email: {
      required,
      email
    },
    form: ['firstName', 'lastName', 'email']
  },
  methods: {
    validate() {
      this.$v.form.$touch();
      var isValid = !this.$v.form.$invalid
      this.$emit('on-validate', this.$data, isValid)
      return isValid
    }
  }
})

Vue.component('step2', {
  template: `<div>
          <div class="form-group" v-bind:class="{ 'has-error': $v.country.$error }">
            <label >Country</label>
         ...