Let's Create a FormKit Plugin Together!
I've been learning how to make FormKit plugins and want to walk you through creating one from scratch. We'll build a plugin that automatically adds icons to inputs - it's a good example because it touches on a lot of key FormKit concepts.
Starting With the Problem
Before diving into code, let's think about what we want to do. I was adding icons to my form inputs manually like this:
<FormKit
type="email"
prefixIcon="email"
/>
For every single input. It was repetitive and I kept forgetting to add them. So I thought - why not make a plugin that does this automatically based on the input type?
Building Our First Plugin
All FormKit plugins start as a function that receives a node. The node is your connection to the input - it has all the properties, methods and lifecycle hooks you need. Here's our starting point:
function addPrefixIconPlugin(node) {
// This is where we'll put our code
}
Adding Lifecycle Hooks
We need to know when our input is created so we can add the icon. FormKit gives us lifecycle events for this:
function addPrefixIconPlugin(node) {
node.on("created", () => {
// This runs when the input is created
});
}
Making Smart Decisions
Now we need some logic to decide if and when to add icons. Let's add some checks:
function addPrefixIconPlugin(node) {
node.on("created", () => {
// Which input types should get icons?
const typesToApply = ["email", "password", "text", "url", "search"];
// Skip if:
if (node.props.prefixIcon) return; // already has an icon
if (!typesToApply.includes(node.props.type)) return; // not an input we care about
if (!node.props.definition) return; // something's wrong
The Hard Part: Modifying the Schema
This is where it gets interesting. FormKit uses something called a schema to build its inputs. Think of it like a blueprint. To add our icon, we need to modify this blueprint:
// Keep the original schema function
const originalSchema = node.props.definition.schema;
// Create our new schema function
node.props.definition.schema = (extensions) => {
// Add our prefix section with the icon
const localExtensions = {
...extensions,
prefix: {
$el: "label",
attrs: {
class: "formkit-prefix-icon formkit-icon",
innerHTML: icons[node.props.type],
},
},
};
// Important! Call the original schema with our changes
return originalSchema(localExtensions);
};
Let's break down what's happening here:
We save the original schema function - we'll need it later
We create a new schema function that adds our prefix section
The prefix section is a label element with our icon
We pass everything back to the original schema function
Putting It All Together
Here's our complete plugin:
function addPrefixIconPlugin(node) {
node.on("created", () => {
const typesToApply = ["email", "password", "text", "url", "search"];
if (node.props.prefixIcon) return;
if (!typesToApply.includes(node.props.type)) return;
if (!node.props.definition) return;
const originalSchema = node.props.definition.schema;
node.props.definition.schema = (extensions) => {
const localExtensions = {
...extensions,
prefix: {
$el: "label",
attrs: {
class: "formkit-prefix-icon formkit-icon",
innerHTML: icons[node.props.type],
},
},
};
return originalSchema(localExtensions);
};
});
}
Using Our Plugin
To use the plugin, we add it to our FormKit config:
import { defaultConfig } from '@formkit/vue'
export default defineFormKitConfig({
plugins: [addPrefixIconPlugin]
})
Now all our inputs automatically get the right icons based on their type!
Key Lessons About Plugin Creation
Through building this, I learned some important things about making FormKit plugins:
Always hook into lifecycle events -
created
,mounted
, etc. Don't try to run your code immediately.Check your conditions early - Get all your
if
checks out of the way at the start, return early if conditions aren't met.Preserve existing functionality - Notice how we kept the original schema function and called it with our changes? That's super important!
Think about overrides - We check for
prefixIcon
first so users can still set their own icons if they want.
Next Steps
Once you understand these basics, you can create all kinds of plugins! Some ideas:
Add custom validation messages
Automatically format certain input types
Add tooltips (which is actually another plugin I made...)
The key is starting small and building up. This icon plugin looks simple but it teaches all the core concepts you need to know.
Let me know if anything's unclear! Plugin development seems scary at first but it's really just about understanding a few core concepts.