FormKit: Vue 3 Form Framework on Steroids

If you’re building a Vue 3 application and have ever wrestled with multiple form components, then you know the struggle. I discoverd this tool whilst on an painstacking search for simple form implementation on my vue applications - Formkit —a game-changing form framework for vue 3. In this article, I’m excited to take you on a deep dive into FormKit and show you why it’s the go-to solution for developers looking to build elegant, efficient forms without the headache.

What is Formkit?

FormKit is an innovative form framework specifically tailored for Vue 3. Unlike traditional UI libraries that simply focus on how things look, FormKit brings a complete toolkit for form building. It wraps up all essential functionalities—from validation and dynamic form generation to seamless styling options—into a single, easy-to-use component. Think of it as your Swiss Army knife for forms: versatile, powerful, and ready to adapt to your unique project needs.

Why FormKit Rules

When it comes to building forms in Vue 3, FormKit offers several standout advantages:

Single Component Simplicity

Imagine handling an entire form with one <FormKit /> component. Yes, you read that right. No more juggling a dozen input elements and endless configuration settings. This single component encapsulates everything from basic input types to more complex structures, making your life as a developer much easier.

Instant Validation Feedback

Validation is crucial—but let’s be honest, writing validation logic can be tedious. FormKit comes with over 30 built-in validation rules that provide instant feedback. Not only does this ensure data integrity, but it also offers a smoother experience for users who get immediate error notifications. Plus, you can extend these rules locally or globally to suit your project’s unique requirements.

Flexible Styling Options

Whether you’re a fan of the default Genesis theme, Tailwind CSS, or your own custom CSS, FormKit is styling-agnostic. This means it seamlessly adapts to whatever design system you’re using. The ability to plug into Tailwind CSS in particular makes it an ideal companion for modern, utility-first design approaches.

Dynamic Schema Generation

Say goodbye to static forms! With FormKit, you can generate forms dynamically using a JSON-compatible schema. This isn’t just a neat trick—it allows you to create forms with conditional logic, loops, and data scoping. In other words, you’re equipped to build complex, dynamic forms without a steep learning curve.

Extensibility and Customization

For developers who love to tinker, FormKit offers hooks, events, plugins, and libraries. This high degree of extensibility means you can craft custom form systems tailored to your project’s needs. It’s a framework that grows with your application and adapts to evolving requirements.

Key Features of FormKit

FormKit isn’t just another form builder; it’s a comprehensive framework designed with both UX and DX in mind. Here are some of its key features:

  1. Single Component Approach: The component wraps everything you need.
  2. Built-In Validation: Over 20 validation rules ensure your forms are robust.
  3. Flexible Styling: Works beautifully with Tailwind CSS, custom styles, or default themes.
  4. Dynamic Schemas: Easily create forms that adapt and change based on your data.
  5. Extensible Architecture: Leverage hooks, events, and plugins to customize behavior.

These features come together to form a tool that significantly reduces development time while enhancing the overall form experience.

Getting Started with FormKit

Ready to give FormKit a spin? Here’s how you can set it up in your Vue 3 project.

Installation

The installation process is straightforward. You simply need to add the FormKit packages via npm:

npm i @formkit/vue @formkit/themes

Integrating with Vue 3

After installing, the next step is to integrate FormKit into your main Vue application file. Open your main.ts (or main.js) file and import FormKit along with the default configuration:

import { plugin, defaultConfig } from '@formkit/vue';
import { createApp } from 'vue';
import App from './App.vue';

createApp(App)
  // ... other plugins
  .use(plugin, defaultConfig)
  .mount("#app");

This simple integration gets you started with a fully functional form framework in your Vue 3 project.

Building a Login Form Example

One of the best ways to understand FormKit is by building a real-world example. Let’s create a login form.

HTML Structure

Here’s how you can structure your login form using FormKit’s single component approach:

<template>
  <!--
    :actions="false" -> To prevent default form actions
    @submit="handleSubmit" -> Submit event triggers the handleSubmit method
  -->
  <FormKit
    type="form"
    id="login-form"
    :actions="false" 
    @submit="handleSubmit"
  >
    <FormKit
      name="email"
      type="email"
      label="Email"
      validation="required|email"
    />

    <FormKit
      name="password"
      type="password"
      label="Password"
      validation="required|length:6"
    />

    <FormKit
      type="submit"
      label="Login"
    />
  </FormKit>
</template>

Handling Form Submission with TypeScript

Now, let’s add the TypeScript code to handle the form submission. In your <script setup lang="ts"> block, include a simple handler:

<script setup lang="ts">
const handleSubmit = (value: any) => {
  console.log("LOGIN FORM: ", value);
};
</script>

With just these few lines, you have a fully operational login form. Of course, you can expand this further with your own business logic.

Configuring FormKit for Your Project

While the default configuration gets you up and running, you might want to customize FormKit’s behavior and appearance. This is where a custom configuration file comes in handy.

Creating a Custom Config File

Create a file called formkit.config.ts in the root of your project. Here’s an example configuration:

import { generateClasses } from "@formkit/themes";

export default {
  config: {
    classes: generateClasses({
      global: {
        outer: 'w-full mb-6',
        label: `
          mb-1
          block
          text-white
          text-base font-quicksand font-normal
        `,
        messages: 'mt-1 mb-0',
        message: 'text-red-500 text-sm font-quicksand font-normal',
        suffixIcon: `w-4 h-4 absolute top-1/2 right-3 transform -translate-y-1/2 text-white`
      },
      form: {},
      text: {
        inner: 'relative',
        input: `
          w-full rounded-md
          px-3 py-[0.32rem]
          outline-0 border border-white bg-transparent
          leading-[1.6] text-white font-quicksand font-medium
        `,
      },
      email: {
        input: `
          w-full rounded-md
          px-3 py-[0.32rem]
          outline-0 border border-white bg-transparent
          leading-[1.6] text-white font-quicksand font-medium
        `
      },
      password: {
        inner: 'relative',
        input: `
          w-full rounded-md
          px-3 py-[0.32rem]
          outline-0 border border-white bg-transparent
          leading-[1.6] text-white font-quicksand font-medium
        `
      },
      submit: {
        input: 'mb-1 mt-4 inline-block w-full rounded-[20px] bg-[#756FF3] px-6 py-2 shadow-md text-base font-medium leading-normal text-white'
      }
    })
  }
}

Merging the Configuration in Your Main File

After creating your configuration file, import it in your main.ts and merge it with the default configuration:

import formkitConfig from '../formkit.config';
import { plugin, defaultConfig } from '@formkit/vue';
import { createApp } from 'vue';
import App from './App.vue';

createApp(App)
  // ... other plugins
  .use(plugin, defaultConfig({
    ...formkitConfig // Merge our custom config into the default configuration
  }))
  .mount("#app");

This setup ensures that your forms will inherit your custom styles and settings across the entire application.

Styling Your FormKit Components

Before you dive into more complex customization, it’s essential to understand the anatomy of a FormKit input field. Every input is structured into several sections, such as the outer container, label, messages, and even icons.

Anatomy of a FormKit Input Field

Consider the example of an email field. In your configuration, you can define a set of classes for different sections:

email: {
  outer: 'w-full mb-6', // Outer div for spacing
  label: `
    mb-1
    block
    text-white
    text-base font-quicksand font-normal
  `, // Label styling
  messages: 'mt-1 mb-0', // Error message wrapper
  message: 'text-red-500 text-sm font-quicksand font-normal' // Specific error message styling
}

This structured approach means that your styles remain consistent throughout your application. You can either apply these globally or override them locally for specific fields.

Integrating FormKit with Tailwind CSS

Tailwind CSS is an excellent match for FormKit due to its utility-first approach. To get started, update your tailwind.config.js to include the FormKit configuration file:

/** @type {import('tailwindcss').Config} */
const formkitTailwind = require('@formkit/themes/tailwindcss');

module.exports = {
  content: [
    "./index.html",
    "./src/**/*.{vue,js,ts,jsx,tsx}",
    "./formkit.config.ts" // Ensure your config file is included in Tailwind's purging process
  ],
  theme: {},
  plugins: [
    formkitTailwind // Add the FormKit Tailwind Theme Plugin
  ],
};

This integration ensures that your custom FormKit classes are compiled into your Tailwind styles, allowing you to harness the full power of Tailwind for your form designs.

Adding New Form Fields

One of FormKit’s most powerful features is its extensibility. Let’s say you want to add a new form field—a select field. The process is as simple as defining its styles and then using it in your form.

Defining the Styles for a New Field

Start by adding a new section in your configuration for the select field:

select: {
  outer: '',
  inner: '',
  input: '',
  // Additional sections as needed
}

Using the Select Field in Your Form

Then, use the new select field in your template:

<template>
  <FormKit
    type="form"
    id="login-form"
    :actions="false" 
    @submit="handleSubmit"
  >
    <!-- Other fields here -->
    <FormKit
      name="select"
      type="select"
      label="City"
      :options="[
        'Windhoek',
        'Gaborone',
        'Cape Town',
      ]"
      validation="required"
    />
  </FormKit>
</template>

This example shows how effortlessly you can extend FormKit with custom fields to meet your project’s specific needs.

Real-World Use Cases and Practical Applications

FormKit isn’t just a neat tool for toy projects—it’s built for real-world applications. Here are a few scenarios where FormKit can be a lifesaver:

  • Rapid Prototyping: When you need to build and iterate on forms quickly, FormKit’s single component and built-in validations save you hours of coding.
  • Production-Level Forms: For complex forms that require dynamic logic, conditional rendering, and custom validation, FormKit’s JSON schema generation and extensibility are indispensable.
  • Custom Form Systems: Whether you’re building a multi-step registration process or a dynamic survey, FormKit can be tailored to your exact requirements.

Enhancing Developer Experience (DX)

One of the standout aspects of FormKit is how it dramatically improves the developer experience:

  • Reduced Code Complexity: With everything packaged into one component, you’re writing less code and reducing potential bugs.
  • Better Debugging: The framework’s clear separation of concerns means errors are easier to track down and fix.
  • Seamless Customization: Hooks, events, and plugins allow you to extend functionalities without getting into the nitty-gritty of each input type.

Tips and Tricks for Using FormKit

Here are a few pointers to get the most out of FormKit:

  • Plan Your Form Schema: Before jumping into code, plan out your form structure and decide which validations and dynamic behaviors you need.
  • Leverage Global Configs: Use the global configuration to ensure consistency across your application. Override only when necessary.
  • Test Validation Extensively: With built-in validation rules, testing is simpler. Still, make sure to write tests for custom rules.
  • Utilize Tailwind: Take full advantage of Tailwind’s utility classes to quickly style your forms without writing custom CSS for every element.
  • Stay Updated: Follow FormKit’s updates and community discussions to learn new best practices and features.

Conclusion

FormKit offers an exciting opportunity to revolutionize how we build forms in Vue 3. Its single component simplicity, built-in validations, dynamic schema generation, and flexible styling options make it a powerful tool for both rapid prototyping and production-level applications. By reducing code complexity and boosting both UX and DX, FormKit allows developers to focus on what matters most—delivering exceptional user experiences with less hassle.

Whether you’re building a simple login form or a complex dynamic survey, FormKit provides the tools and flexibility to handle it all. With its seamless integration with Tailwind CSS and robust configuration options, FormKit not only meets but exceeds the demands of modern web development.

In summary, if you’re looking to enhance your Vue projects with an intuitive and powerful form framework, FormKit is the answer. It’s more than just a UI library—it’s a comprehensive toolkit that empowers you to build forms that are both visually appealing and functionally robust. Happy coding!