DEV Community

Florian
Florian

Posted on

Why I built Vorm – a schema-based form engine for Vue 3 that doesn’t get in your way

Forms.

They’re everywhere.

Even when typing a URL, technically, you’re already interacting with one.

But let’s not get dramatic. 😄

Still, on nearly every site, every web app, we deal with forms in one way or another.

Login screens. Registration. Profile settings. Blog editors. Ordering a pizza.

Forms are not the enemy.

But something changed for me when I had to work on a massive form with over 120 fields, many of which were conditionally shown or enabled depending on other values:

"If select A has value X, then select B must be Y, and input Z disappears."

It was thousands of lines of code.

Not elegant. Not maintainable.

Just glue code to bind state, validation, conditional rendering, wrappers, etc.

At that point I asked myself:

Why do we keep doing this over and over again?

Why do I have to handcraft even the simplest login form or settings page from scratch —

or adopt a huge validation framework just to validate a checkbox?

Most forms are not special.

They follow simple patterns.

I realized: 90% of forms could be auto-generated, if we just had a tool that stays out of your way.

So I decided to build one.


I like schemas. I like types. I like simplicity.

And that’s what Vorm is built on.

At its heart is a reusable schema that defines everything:

  • fields
  • layout
  • validation
  • conditional logic
  • even styling

You define the schema once.

Then drop in a component like <AutoVorm />, maybe pass in a few props – and you're done.

No input spamming. No boilerplate. No magic.

Just clean, explicit structure.

But that wasn’t enough.

Vorm had to be flexible too. Because when the 90% doesn’t cut it —

you still need 100% control.

And so that’s how Vorm works:

  • Use AutoVorm for fast results.
  • Use useVorm() when you need full programmatic control.
  • Use wrappers, slots and your own components to style anything.

What Vorm became

A single schema — used everywhere.

Want to hide a field? showIf.

Want to change the wrapper component? Use the wrapper slot.

Want to inject your own field renderer? Go ahead.

And most importantly:
You always have full access to the reactive form data and validation state.

Here is a short example:

Define your scheme in script

const schema: VormSchema = [
  {
    name: 'username',
    label: 'Username',
    type: 'text',
    validation: [{ rule: 'required' }],
  },
  {
    name: 'email',
    label: 'Email address',
    type: 'email',
    validation: [{ rule: 'required' }, { rule: 'email' }],
  },
  {
    name: 'password',
    label: 'Password',
    type: 'password',
    validation: [{ rule: 'required' }],
  },
  {
    name: 'notes',
    label: 'Notes',
    type: 'textarea',
  },
  {
    name: 'role',
    label: 'Role',
    type: 'select',
    validation: [{ rule: 'required' }],
  },
  {
    name: 'adminCode',
    label: 'Admin code',
    type: 'text',
    showIf: { role: 'Admin' },
  },
  {
    name: 'tos',
    label: 'Accept terms',
    type: 'checkbox',
    validation: [{ rule: 'required' }],
  },
];
Enter fullscreen mode Exit fullscreen mode

And then all you have to do is this:

<VormSection title="Basic Example" titleClasses="text-xl font-bold">
  <AutoVorm layout="grid" :columns="2" />
</VormSection>
Enter fullscreen mode Exit fullscreen mode

To get this:

Vorm result


What happened to the 120-field beast?

I rebuilt that monstrous form in a separate project using Vorm.

It took some time — and honestly, it broke Vorm a few times. 😅

But that’s when Vorm started becoming real.

I moved all the logic into the schema. The template shrunk down to maybe 30–40 lines.

And the performance?

All 120 fields, fully validated, in under 20ms on cold start.

No debounce hacks. No suspense loading. Just solid reactive performance.


So… just another form library?

No. Or, yes — but one that does it differently.

Yes, Vorm is "another" form engine.

But it’s one that:

  • doesn’t force you into rigid components,
  • doesn’t ship with opinionated styling,
  • doesn’t rely on global mixins or massive plugins.
  • has only 51kB package size and uses "no" other dependencies

It’s not perfect.

  • The schema is strongly typed, but can be better.
  • File inputs aren’t natively supported yet (though you can easily render them via slots or wrappers).
  • It’s still very young — but very alive.

That’s why Vorm is currently in Alpha.

Not ready for your enterprise CRM.

But absolutely ready for small projects, experiments, side apps — and community feedback.


I want your thoughts

If you’ve ever written a form and thought

“Why am I still manually doing this?”

Then Vorm might be worth a look.

Try it.

Break it.

Tell me what doesn’t work.

Let’s shape this thing together, before it hits v1.0.

🧪 GitHub: https://github.com/Flo0806/vorm

📘 Docs: https://vorm.fh-softdev.de

🎮 Playground: Basic Example Real-World Example


Thanks for reading — and if this resonated with you, feel free to ⭐️ it or leave a comment.

Let’s make forms fun again. 🚀

Top comments (1)

Collapse
 
anna_heuberger_d48c5e50a9 profile image
Anna Heuberger

What a nice and clean way to simplify this. This is a huge gamechanger! Thanks for sharing!

Some comments may only be visible to logged-in visitors. Sign in to view all comments. Some comments have been hidden by the post's author - find out more