Published on

Create multi-step Vue.js form with send data and get email notification


Multi-step Vue.js form

In this article, we going to create a dynamic multi step Vue.js form, without backend. This form contains stepper, thank you text and loading animation. We will handle submissions via Getform.

Getform Dashboard

Getform Dashboard

Form email notification

Getform send email

Other Examples

Create dynamic form with React.js

Create dynamic form on static website

Form Notifications

Send Slack notification from your HTML form

Send Email notification from your HTML form

Getting Started

Create account on Getform

Create Vue.js project

Install Tailwind CSS with Vite


Tailwind CSS Components

I created simple design with Tailwind. Here is our element styles:

/* index.css */

@tailwind base;
@tailwind components;
@tailwind utilities;

@layer components {
  ._btn-white {
    @apply p-2 flex items-center justify-center text-gray-800 bg-gray-50 border border-transparent rounded-md font-medium w-full hover:bg-gray-200 hover:no-underline;
  ._btn-bordered {
    @apply p-2 flex items-center justify-center text-gray-50 border border-gray-50 rounded-md font-medium text-center cursor-pointer w-full hover:bg-gray-50 hover:text-black hover:no-underline;
  ._input {
    @apply text-gray-50 mb-3 w-full bg-slate-700 py-2 px-3 rounded-md outline-none border border-transparent focus:border-gray-400 focus:border;
  ._title {
    @apply font-semibold text-gray-50 text-left w-full text-2xl mb-4;
  ._sub-title {
    @apply text-gray-400 text-sm mb-2;

Form body with stepper

<div class="flex items-center justify-start flex-col w-full h-full max-w-[350px] max-h-[310px]">
    <Transition name="fade" mode="out-in">
    <div v-show="steps == 1 || steps == 2"
        class="w-full mb-4">
        <h1 class="_title">Appeal Request Form</h1>
        <!-- Stepper -->
        <div class="flex items-center justify-between [&>p]:text-xs [&>p]:pb-1 [&>p]:font-semibold [&>p]:w-full [&>p]:cursor-pointer [&>p]:border-b-[5px] [&>p]:flex [&>p]:items-center [&>p]:justify-between">
                @click="steps = 1"
                :class="[steps == 1 ? 'text-gray-50 border-gray-50' : 'border-green-300 text-green-300']">
                1. Provider
                <span v-show="steps == 2 || isLoading == true"></span></p>
                @click="steps = 2"
                [(steps == 1 ? 'border-b-gray-700 text-gray-700' : 'text-gray-50 border-gray-50'), 
                (isLoading == true ? 'border-green-300 text-green-300' : '')]
                2. Member 
                <span v-show="isLoading == true"></span>
        <!-- Stepper-end -->
    <form class="relative w-full" @submit="formSubmit">
    <Transition name="fade" mode="out-in">
        <!-- Step 1 -->
        <div class="flex flex-col" v-if="steps == 1">
            <p class="_sub-title">Provider Information</p>
            <input name="provider-name" v-model="providerName" class="_input" type="text"
                placeholder="Provider Name">
            <input name="provider-number" v-model="providerNumber" class="_input" type="text"
                placeholder="Provider Number">
            <input name="member-name" v-model="memberName" class="_input" type="text"
                placeholder="Member Number">
            <input name="full-name" v-model="fullName" class="_input" type="text" placeholder="Full Name">
            <p @click="steps = 2" class="_btn-bordered">
                Next -></p>  <!-- This button changes steps value 1 to 2.  -->
        <!-- Step 1-end -->

        <!-- Step 2 -->
        <div class="flex flex-col" v-else-if="steps == 2">
            <p class="_sub-title">Member Information</p>
            <input name="email" v-model="email" class="_input" type="text" placeholder="Email">
            <input name="phone" v-model="phone" class="_input" type="text" placeholder="Phone">
            <input name="birth" v-model="birth" class="_input" type="text" placeholder="Date of birth">
        <div class="relative">
            <i class="arrow"></i>
            <select class="_input" name="country" id="country" required>
            <option disabled selected value="">Country</option>
            <option value="uk">United Kingdom</option>
            <option value="us">United States</option>
            <option value="other">Other</option>
        <div class="flex items-center justify-between">
            <button type="submit" :class="{ 'bg-gray-400 pointer-events-none': isLoading }" class="_btn-white">
                <div v-show="isLoading"
                    class="animate-spin w-5 h-5 rounded-full border-2 border-l-white/20 border-t-white/20"></div>
                <p class="font-medium" v-show="!isLoading">Submit</p>
        <!-- Step 2-end -->

        <!-- Step 3 / Show thank you text if response status 200 -->
        <div v-else class="flex items-center justify-center flex-col">
        <p class="text-4xl text-green-400"></p>
        <h3 class="text-gray-50 font-bold text-2xl">Thank you</h3>
        <p class="text-gray-400 text-md">Your message has been sent.</p>
        <!-- Step 3-end -->

<!-- This css changes default arrow of select and color of disabled option -->
<style scoped>
    select {
        appearance: none;

    .arrow {
        display: inline-block;
        position: absolute;
        padding: 2px;
        right: 15px;
        z-index: 10;
        top: 17px;
        border: solid #9ca3af;
        border-width: 0 1.5px 1.5px 0;
        transform: rotate(45deg);
        -webkit-transform: rotate(45deg);

    select:required:invalid {
        color: #9ca3af;

Handle submissions with Getform

Getform is a modern form backend platform that lets you handle your forms on your websites and apps. You can create a form endpoint and start collecting submissions within minutes without having to setup a server or write any backend. Getform is perfect for static sites and works anywhere you can put an HTML form.

Get Started

  • Create account on Getform
  • Verify your email
  • Click + Create... button on side bar
  • Create your form endpoint
  • Copy your form endpoint

I wrote all states. You can easly do form validation with these states. Our JavaScript code should be look like this:

export default {
  data() {
    return {
      steps: 1,
      isLoading: false,
      providerName: null,
      providerNumber: null,
      memberName: null,
      fullName: null,
      email: null,
      phone: null,
      birth: null,
  methods: {
    formSubmit(e) {

      this.isLoading = true // Set submit button as loading/disabled when submit

      const formData = new FormData();

      fetch("https://getform.io/f/{your-endpoint-goes-here}", {
        method: "POST",
        body: formData,
        .then(response => {
          if (response.status === 200) {
            this.steps = 3 // Show thank you text if response status 200
        .catch(error => console.log(error))


  • avatar
    Umur Köse