DEV Community

Cover image for How to Unlock Formkit Multistep forms on a Laravel Inertia app with Vue 3
Sam
Sam

Posted on • Originally published at mizouzie.dev

How to Unlock Formkit Multistep forms on a Laravel Inertia app with Vue 3

Formkit offers a great Multi-Step tool for building forms in your Vue app, but getting it to work inside a Laravel Inertia app is a little tricky. Here is how to get it running.

Formkit logo from Vue School

Formkit is a supercharger for developing applications on the already turbo platform of Laravel Inertia with Vue 3. It is a library of ready made components for building forms that make it very easy to construct any kind of form for retrieving user input. One of the features of this library that stood out the most for me was the Multi-Step forms.

Multi-Step Forms

So what is a multi-step form?

It is a format that breaks the usual monotony of filling out a form for the user. It splits the form into smaller form-lets that helps to give a much nicer UX because they're not faced with such a huge list of questions all at once. The multi-step form can be split and navigated by tabs or a progress-map that resembles a London Underground map 😍

An example of Formkit Multi-Step

So as developers, we want to provide this kind of experience for our application users. Formkit is a very well provided for library with extensive documentation for it's implementation into a standard Vue 3 project, but when I tried to put it into a Laravel Inertia app using Vue 3, it needed a little thinking outside of the dox.

Installing Formkit

What do the docs say?

Here you can check the Vue specific docs for the initial Formkit installation. They are nice and straightforward, but following these to the letter does not give us the desired result.

We will install with npm:

npm install @formkit/vue
Enter fullscreen mode Exit fullscreen mode

The slight difference for Inertia

Now to get it working in our case, we need to have our app.js looking like this:

import './bootstrap';
import '../css/app.css';

import { createApp, h } from 'vue';
import { createInertiaApp } from '@inertiajs/vue3';
import { resolvePageComponent } from 'laravel-vite-plugin/inertia-helpers';
import { ZiggyVue } from '../../vendor/tightenco/ziggy/dist/vue.m';
import { plugin as formkitPlugin, defaultConfig } from '@formkit/vue';

const appName = window.document.getElementsByTagName('title')[0]?.innerText || 'Laravel';

createInertiaApp({
    title: (title) => `${title} - ${appName}`,
    resolve: (name) => resolvePageComponent(`./Pages/${name}.vue`, import.meta.glob('./Pages/**/*.vue')),
    setup({ el, App, props, plugin }) {
        return createApp({ render: () => h(App, props) })
            .use(plugin)
            .use(ZiggyVue, Ziggy)
            .use(formkitPlugin, defaultConfig)
            .mount(el);
    },
    progress: {
        color: '#4B5563',
    },
});
Enter fullscreen mode Exit fullscreen mode

The slight tweaks are evident on the import and then that same tweak is repeated inside the use() before the app is mounted.

As we need to import "plugin" from formkit and we already have a "plugin" named in our setup() function, it is necessary to give the Formkit imported "plugin" an alias. Then later down the chain of use()'s, we can provide that alias.

Installing Multi-Step addon

What do the docs say?

Here you can check the official docs for installing the Multi-Step addon for Formkit.

TLDR: It suggests the use of a formkit.config.js file, which is fine if you're just using Vue... but we're not!

One other thing to note, is that it's not very obvious that you actually need to install this separately with:

npm i @formkit/addons
Enter fullscreen mode Exit fullscreen mode

The slight difference for Inertia

As you may have noticed, we've seen a part of that before. The importing defaultConfig was in our first setup. We will use that to our advantage and do so inline stuff to get where we want to be.

import './bootstrap';
import '../css/app.css';
import '@formkit/addons/css/multistep';

import { createApp, h } from 'vue';
import { createInertiaApp } from '@inertiajs/vue3';
import { resolvePageComponent } from 'laravel-vite-plugin/inertia-helpers';
import { ZiggyVue } from '../../vendor/tightenco/ziggy/dist/vue.m';
import { plugin as formkitPlugin, defaultConfig } from '@formkit/vue';
import { createMultiStepPlugin } from '@formkit/addons';

const appName = window.document.getElementsByTagName('title')[0]?.innerText || 'Laravel';

createInertiaApp({
    title: (title) => `${title} - ${appName}`,
    resolve: (name) => resolvePageComponent(`./Pages/${name}.vue`, import.meta.glob('./Pages/**/*.vue')),
    setup({ el, App, props, plugin }) {
        return createApp({ render: () => h(App, props) })
            .use(plugin)
            .use(ZiggyVue, Ziggy)
            .use(formkitPlugin, defaultConfig({
                plugins: [createMultiStepPlugin()],
            }))
            .mount(el);
    },
    progress: {
        color: '#4B5563',
    },
});
Enter fullscreen mode Exit fullscreen mode

As you can see, we've added;

  • a CSS import
  • an addon module import
  • that extra module inside the previously added defaultConfig

Using Formkit

Now that it is setup, we are free to use the super speedy form building tool to it's fullest potential, stacking form sections in beautiful multi-step glory. For example:

<script setup>
import PrimaryButton from '@/Components/PrimaryButton.vue';
import SecondaryButton from '@/Components/SecondaryButton.vue';
import { FormKit } from '@formkit/vue';

function clearForm() {
    // Your clear form handler
}

function submitForm() {
    // Your submit handler
}
</script>

<template>
    <FormKit type="form" :actions="false">
        <FormKit type="multi-step" tab-style="progress">
            <FormKit type="step" name="csv">
                <FormKit type="file" label="Spreadsheet" accept=".xls,.xlsx,.csv,.txt" validation="required"
                    help="Upload a csv, xls or xlsx file." />
                <div class="my-6">
                    When a csv file is uploaded here, we will read the heading row so that you can choose from the list on
                    the next section of this form which columns contain the variable values.
                </div>

            </FormKit>
            <FormKit type="step" name="columns">
                <FormKit type="text" label="Columns" validation="required" />

            </FormKit>
            <FormKit type="step" name="rows">
                <FormKit type="text" label="Rows" validation="required" />

            </FormKit>
            <FormKit type="step" name="maxLength">
                <FormKit type="number" label="Max Length" :value="500" validation="required" />

            </FormKit>
            <FormKit type="step" name="submit">
                <SecondaryButton :onClick="clearForm">
                    Cancel
                </SecondaryButton>

                <PrimaryButton :onclick="submitForm">
                    Submit
                </PrimaryButton>
            </FormKit>
        </FormKit>
    </FormKit>
</template>
Enter fullscreen mode Exit fullscreen mode

For the full documentation on actually using Formkit (now that it's working 😉) click here

Happy Form-Building!

Top comments (2)

Collapse
 
gustavofenilli profile image
Gustavo Fenilli

Hey, I'm from the FormKit team and there is a first party addon to integrate InertiaJS with FormKit called formkit-addon-inertia.

There is some work to make it work better and easier for people who already use Inertia, as having a better composable in line with useForm.

Would love to hear about what features would you like it implemented.

Collapse
 
mizouzie profile image
Sam

That sounds like EXACTLY the thing I was hoping for. useForm was the part that I was hoping to tie in with.

As I did not see the package mentioned in the docs I just went ahead with what was there. I’ll have to check it out and maybe make some adjustments to my project.

Thanks a lot for letting me know!