Few interactions on the web cause as much displeasure for a user as being confronted with a large, intimidating form. Multi-step forms can alleviate this pain by breaking a large form into smaller, approachable steps — but they can also be quite complicated to build.
In this guide, we'll walk through building a multi-step form with FormKit (a free and open-source form building framework) and see how we can provide an elevated user experience with minimal code. We'll be done in approximately 5 minutes. Let's get started!
Not familiar with FormKit? It's a free and open-source framework for building forms in Vue and you can learn more about it here.
Installation
To get started we need to install FormKit, its supporting default theme, and the FormKit Multi-Step plugin into our project:
npm install @formkit/vue @formkit/addons @formkit/themes
Then we add FormKit to our Vue app, add the Multi-Step Plugin to our FormKit config, and ensure that we're including the necessary styles:
// main.js
import { createApp } from 'vue'
import App from 'App.vue'
// FormKit imports
import { plugin as formKitPlugin, defaultConfig } from '@formkit/vue'
import { createMultiStepPlugin } from '@formkit/addons'
import '@formkit/themes/genesis'
import '@formkit/addons/css/multistep'
createApp(App)
.use(formKitPlugin, defaultConfig({
plugins: [createMultiStepPlugin()]
}))
.mount('#app')
Usage
Out-of-the-box, FormKit ships with every native HTML input available to you. Things like text
, select
, checkbox
, etc.
createMultiStepPlugin
registers two brand-new input types for you to use with FormKit — in exactly the same way you use any other input type.
-
multi-step
: The wrapping group for the entire multi-step input. -
step
: The wrapping group for a given step within your multi-step input.
Using these inputs together is as simple as wrapping any markup you want to have present within a step in a multi-step form:
<FormKit type="multi-step">
<FormKit type="step" name="stepOne">
<!-- content for stepOne goes here! -->
</FormKit>
</FormKit>
So — let's build a quick form for users who want to submit a talk to our upcoming fake conference, VueUniverse.
We'll want to:
- Collect some contact information for the user.
- Get a brief overview of the talk the user wants to give.
- Ask the user how they heard about VueUniverse.
Those sound like good groupings for our steps — so let's get started:
<FormKit type="form">
<FormKit type="multi-step">
<FormKit type="step" name="contactInformation">
<!-- collect name, email, and company info -->
<FormKit
type="text"
label="Your Name"
validation="required"
/>
<FormKit
type="email"
label="Your Email"
validation="required|email"
/>
<FormKit
type="text"
label="Your Company (optional)"
help="Are speaking on behalf of an organization?"
/>
</FormKit>
<FormKit type="step" name="talkDetails">
<!-- Get talk title, brief, and track -->
<FormKit
type="text"
label="Talk Title"
validation="required"
/>
<FormKit
type="textarea"
label="Talk Brief"
validation="required|length:100"
help="What is your talk about?"
/>
<FormKit
type="radio"
label="Talk Track"
help="Which track are you submitting for?"
:options="['Development', 'Testing', 'Leadership']"
/>
</FormKit>
<FormKit type="step" name="referral">
<!-- Ask the user to share how they heard about us -->
<h2>Thank you for taking the time to submit your talk</h2>
<p>If you don't mind we'd love to know how you heard about VueUniverse.</p>
<FormKit
type="radio"
label="How did you hear about VueUniverse?"
:options="['Online Ad', 'Friend or Coworker', 'Search Results', 'Other']"
/>
</FormKit>
</FormKit>
</FormKit>
And there we go! One component, FormKit
, with a consistent API and we've got ourselves a working multi-step form with validation!
(for the best experience open this example in a new tab)
That's great! But there's two things we can change to make it better.
- Since we're using the
multi-step
input as our entire form experience it would be great to have the submit button be inside the last step rather than external to themulti-step
input. - We're asking users to go through a set flow, so it would be great if our tabs indicated progress. Additionally it would be great if we prevented the user from navigating to the next step until the current step is completed.
Thankfully, these are both very easy changes to implement.
- First we need to set
:actions="false"
on our wrappingform
typeFormKit
component to disable the default submit button. Then, using thestepNext
slot we can insert our own submit button inside the last step in our multi-step form. - Second, we need to use the
tab-style="progress"
andallow-incomplete="false"
props to show progress-style tabs and prevent the user from freely navigating through steps until validation is passed.
Here are the relevant sections of our form with those changes implemented:
<!-- remove default actions on the form -->
<FormKit
type="form"
:actions="false"
>
<!-- Set new props on our multi-step -->
<FormKit
type="multi-step"
tab-style="progress"
:allow-incomplete="false"
>
...
<!-- In our last step, add a submit button -->
<FormKit type="step" name="referral">
...
<template #stepNext>
<FormKit type="submit" />
</template>
</FormKit>
</FormKit>
</FormKit>
And again, that's it! FormKit takes care of the rest for us. Here is our new and improved multi-step form experience after changing those 6 lines of code.
(for the best experience open this example in a new tab)
Best of all this form has accessible markup, built-in validation, and much more that we didn't have to worry about ourselves thanks to the underlying FormKit component architecture.
Conclusion
Quick, easy, powerful. Implementing a multi-step form in your project has never been simpler.
By leveraging FormKit in your Vue projects you can supercharge your form development and build rich and complex user-experiences in a fraction of the time — for free.
Want to learn more about FormKit and how it can help with form structure, validation, accessibility, and more?
- Check out the multi-step docs at https://formkit.com/plugins/multi-step
- Join the FormKit Discord community for support and to meet others using FormKit in their own projects: https://discord.gg/2q3UZkUQbR
Top comments (3)
Thanks 🙏
Just a question
How to integrate Formkit Multi Step with URL query params?
and How to validate URL query params when user add a key that does not exist in form
It would be nice if you add this example
So with FormKit you can pass the
value
prop to your<FormKit type="form">
component and all of the values will be propagated to the nested inputs based on input name / grouping.So for params, you would do some sort of setup work where you fetch the params from the url, and then re-assemble your data object that you want to provide to
values
. If a matching FormKit node does not exist in your form the that value will be ignored.You can read more about form data population here: formkit.com/inputs/form#populating
Exactly what I was looking for, thanks a million for sharing!