@directorkit/forms

Reactive form model for Nuxt — controls, groups, validators and transformers. A Nuxt layer with no components.
Install
npm install @directorkit/forms
Latest Version:0.1.2
Vue:3
License:MIT
Last Updated:Oct 6, 2026
Links: GitHub  ·  npm
Maintainer: thomasparsley

@directorkit/forms

A reactive form model for Nuxt: controls, groups, validators and transformers. Logic-only — it ships no components. Pair it with @directorkit/form-ui to bind the model to real inputs, or drive your own.

Install

npm install @directorkit/forms
// nuxt.config.ts
export default defineNuxtConfig({
  extends: ["@directorkit/forms"],
});

@directorkit/forms is a Nuxt layer, not a built library: it ships raw source and the consuming app's Vite compiles it. nuxt and vue are peer dependencies.

The model

Four composed abstractions, with state living only at the leaves:

useFormControl(initial, options) One field: value, status, validators, transformers
useFormGroup(controls) A record of controls (or nested groups); aggregates status and data
useArrayFormGroup(factory) A growable list of groups — add/remove rows
useKvForm(...) A key/value form for dynamic, non-fixed shapes
useFormSubmit(form, handler) Validate-then-submit, returning a callback for post-success work
const form = useFormGroup({
  email: useFormControl("", {
    validators: [requiredValidator(), emailValidator()],
    transformers: [stringTrimTransformer],
  }),
  age: useFormControl<number | null>(null, {
    validators: [numberRangeValidator({ min: 18 })],
  }),
});

const { executeSubmit, isDisabled, isLoading } = useFormSubmit(form, async data => {
  await $fetch("/api/users", { method: "POST", body: data });
  // Return a function to run only after a successful submit (ADR-0014).
  return () => navigateTo("/users");
});

useFormSubmit validates before it calls you, guards against double submits, and drives isDisabled / isLoading for the button — a form that is untouched, pending or invalid disables itself.

Three conventions are worth knowing before you write against it:

  • null is the empty value. undefined never enters the model, so "untouched" and "explicitly cleared" stay distinguishable (ADR-0012).
  • patch(data, { write: true }) is the hydration primitive — load an API response into a form without marking it dirty (ADR-0011).
  • Validators do one thing each and come in eager and lazy flavours; the same split exists for transformers (ADR-0013).

Batteries included under validators/ — requiredValidator, emailValidator, valueEqualsToValidator, stringMinLengthValidator, stringMaxLengthValidator, numberRangeValidator, numberPositiveIntegerValidator, dateBeforeValidator, dateBeforeOrEqualValidator, arrayItemsValidator, arrayOneOfValidator, arrayLengthValidator — and under transformers/: stringTrimTransformer, stringEmptyAsNullTransformer, valueEmptyAsNullTransformer, arrayEmptyAsNullTransformer, objectEmptyAsNullTransformer, numberEnsureTransformer.

Documentation

The model is specified in the repo's ADRs: 0010 (the forms model) first, then 0011 – 0014.

License

MIT © Tomáš Petržela

Related Packages

@formkit/core

The framework agnostic core of FormKit

6,311,049 4,779
@formkit/inputs

Commonly shared types for FormKit

5,256,579 4,779
@formkit/observer

Utility to wrap a FormKitNode in a dependency tracking observer proxy

5,049,667 4,779
@formkit/validation

Validation plugin for FormKit

5,032,259 4,779

Version History

Version Released Vue License
0.1.2 ^3.5 MIT
0.1.1 ^3.5 MIT
0.1.0 ^3.5 MIT