Skip to content
Development
Skill

/web-forms-vee-validate

VeeValidate v4 patterns - useForm, useField, defineField, useFieldArray, schema validation with Composition API

From plugin
agents-inc-skills
24200 skills
Install
$ npx -y skills add agents-inc/skills --skill web-forms-vee-validate --agent claude-code

How it fires

How this skill gets triggered: by you, by Claude, or both.

  • Fires itselfAuto-invocation. Claude auto-loads it when your prompt matches the work.Auto-invocation is when the right skill fires by itself at the right moment, driven by a FLOW.md router and a hook, instead of you invoking it by name. It is the difference between a skill being installed and a skill actually getting used.Read the full definition →
  • You can call itInvoke it directly when you want it.
  • Slash command/web-forms-vee-validate

Context preview

The summary Claude sees to decide when to auto-load this skill.

VeeValidate v4 patterns - useForm, useField, defineField, useFieldArray, schema validation with Composition API

SKILL.md

web-forms-vee-validate.SKILL.md
name: web-forms-vee-validate
description: VeeValidate v4 patterns - useForm, useField, defineField, useFieldArray, schema validation with Composition API

VeeValidate Form Validation Patterns

> **Quick Guide:** `useForm` owns the form state; `defineField` returns a `[model, attrs]` tuple to > `v-model` onto a native input, and `useField` binds a field inside a reusable input component — > with its name passed as a getter so it stays reactive. A schema reaches `validationSchema` through > `toTypedSchema()`, which is also what supplies the types. `useFieldArray` drives repeatable groups > and iterates on `field.key`. Everything here is v4; v5 removes the adapter, so check > [reference.md](reference.md) before targeting it.

**Detailed Resources:**

  • [examples/core.md](examples/core.md) — `defineField`, inline rules, a reusable input built on `useField`, form meta, eager validation
  • [examples/validation.md](examples/validation.md) — schema through `toTypedSchema`, conditional schemas, all errors per field
  • [examples/arrays.md](examples/arrays.md) — `useFieldArray`, nested arrays, reordering
  • [reference.md](reference.md) — return-value tables, composition helpers, worked anti-patterns, v5 migration

---

Which path applies

  • **The form is built in the component around native inputs** — `useForm` plus `defineField`, and

`v-model` on the returned model. Follow [examples/core.md](examples/core.md).

  • **A reusable input component** — `useField` inside the component, taking its name as

`() => props.name`. Follow [examples/core.md](examples/core.md) Pattern 3.

  • **The renderless `<Form>` and `<Field>` components** — an alternative to the Composition API

rather than a companion to it. Each creates its own form context, so a component that calls `useForm` and also renders `<Form>` has two, and the fields register with whichever they are nested in.

---

<critical_requirements>

Before writing VeeValidate code

**Wrap a schema in `toTypedSchema()` before handing it to `validationSchema`.** The adapter converts the schema's result into the shape the form reads and is what supplies the value types; a raw schema is accepted without complaint and then validates nothing.

**Pass `useField` its name as `() => props.name` or `toRef(props, "name")`.** A plain `props.name` is read once at setup, so the field keeps binding to the name the component first mounted with.

**Give `initialValues` an entry for every field, arrays included.** Field arrays iterate their value and fail on `undefined`, and a cross-field rule is skipped entirely when one of the keys it compares is missing.

**Iterate `useFieldArray` on `field.key`.** It is the identity VeeValidate assigns each entry and it survives insertion and reordering, which a positional index does not.

</critical_requirements>

---

**Auto-detection:** vee-validate, @vee-validate/zod, @vee-validate/yup, @vee-validate/valibot, useForm, useField, defineField, useFieldArray, toTypedSchema, validationSchema, errorBag, handleSubmit, resetForm, setFieldError, setErrors, validateOnValueUpdate, keepValuesOnUnmount, ErrorMessage, useFormContext

**Applies to:**

  • Vue form state, validation timing and submission
  • Reusable input components that bind themselves to a named field
  • Repeatable field groups that add, remove and reorder
  • Surfacing server-side validation failures against individual fields
  • Multi-step forms where fields unmount between steps

**Handled elsewhere:**

  • Authoring the validation schema — `toTypedSchema` adapts whatever schema it is given, and how that

schema states its rules is settled by whatever owns it.

  • Choosing a schema library — an adapter package exists for each, and the choice sits outside this

skill.

  • Markup and styling of the inputs — every example uses plain elements, so the classes are yours.
  • Where the initial values came from — `initialValues` is a plain object the form does not fetch.

---

<philosophy>

Validation is declared once, at the form, and read per field. `useForm` holds the schema and the values; each field asks the form for its own slice, so a field knows its error without knowing the rule that produced it. That is what lets an input component be written without knowing which form it will be dropped into — it takes a name and binds itself.

Reactivity is the thing to keep intact. Everything a field receives from the form is a ref or a getter, and the common failure is flattening one of them: reading `props.name` instead of passing a getter, or unwrapping a computed schema with `.value` before the form can track it.

</philosophy>

---

<decision_framework>

defineField or useField

| | `defineField` | `useField` | | ------------ | ------------------------------------------- | --------------------------------------------- | | Returns | `[model, attrs]` for `v-model` and `v-bind` | `value`, `errorMessage`, `meta`, handlers | | Form context | Required — it comes off a `useForm` result | Optional; falls back to standalone validation | | Best for | The form's own template, native inputs | A component that binds itself by name |

`defineField` where the form and the inputs are in one component. `useField` where the input is a component in its own right, or where the binding needs handlers rather than a `v-model`.

</decision_framework>

---

<patterns>

Core patterns

Pattern 1: useForm with defineField

`defineField` returns a tuple: the model for `v-model`, and the attrs carrying the event handlers that drive validation timing.

<script setup lang="ts">
const { handleSubmit, errors, defineField } = useForm({
  validationSchema: schema,
  initialValues: { email: "", password: "" },
});

const [email, emailAttrs] = defineField("email");

const onSubmit = handleSubmit(async (values) => {
  await login(values);
});
</script>

<template>
  <input v-model="email" v-bind="em
Read more
Ships withagents-inc-skills

The official skills marketplace for Agents Inc. 150+ skills covering everything from React and Prisma to Redis, ElevenLabs, and infrastructure tooling. Pick the skills that match your stack and install them via Claude Code. Need more control?

Get the whole plugin

Other skills on agents-inc-skills.