본문으로 건너뛰기
cccskills
무료GitHub에 공개

web-forms-vee-validate

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

한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.

설치 방법 보기

포함된 파일(6)

  • SKILL.md11.0 KB
  • examples/arrays.md15.0 KB
  • examples/core.md11.9 KB
  • examples/validation.md9.0 KB
  • metadata.yaml367 B
  • reference.md12.7 KB

SKILL.md(원문)

설치하기 전에 에이전트에게 전달되는 지시 내용을 확인할 수 있습니다.

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 before targeting it.

Detailed Resources:

  • examples/core.md — defineField, inline rules, a reusable input built on useField, form meta, eager validation
  • examples/validation.md — schema through toTypedSchema, conditional schemas, all errors per field
  • examples/arrays.md — useFieldArray, nested arrays, reordering
  • 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.
  • A reusable input component — useField inside the component, taking its name as () => props.name. Follow 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

defineFielduseField
Returns[model, attrs] for v-model and v-bindvalue, errorMessage, meta, handlers
Form contextRequired — it comes off a useForm resultOptional; falls back to standalone validation
Best forThe form's own template, native inputsA 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="emailAttrs" />
  <span v-if="errors.email" role="alert">{{ errors.email }}</span>
</template>

Dropping v-bind="emailAttrs" leaves the model bound but the handlers unattached, so the field never blurs and never validates.

Full code: examples/core.md Pattern 1


Pattern 2: useField in a reusable input

The name arrives as a getter so the field re-binds if the prop changes.

<script setup lang="ts">
const props = defineProps<{ name: string }>();

const { value, errorMessage, handleBlur, handleChange, meta } =
  useField<string>(() => props.name, undefined, {
    validateOnValueUpdate: false,
  });
</script>

validateOnValueUpdate: false holds validation back to blur, which is what stops errors appearing while the user is still typing the first character.

Full code: examples/core.md Pattern 3


Pattern 3: Schema through toTypedSchema

The adapter is the boundary: the schema states the rules, and toTypedSchema renders them as VeeValidate errors and as the type of values.

import { toTypedSchema } from "@vee-validate/zod";

const schema = toTypedSchema(registrationSchema);

const { handleSubmit, errors } = useForm({
  validationSchema: schema,
  initialValues: { email: "", password: "", confirmPassword: "" },
});

Every key a cross-field rule compares needs an entry in initialValues — a rule reading a key that is undefined is skipped rather than failed, so the form submits as valid.

Full code: examples/validation.md


Pattern 4: useFieldArray

fields carries a key and a value per entry. The key is the iteration key; the value is what the inputs bind to.

<script setup lang="ts">
const { handleSubmit } = useForm({
  initialValues: { users: [{ name: "", email: "" }] },
});

const { fields, push, remove } = useFieldArray("users");
</script>

<template>
  <div v-for="(field, index) in fields" :key="field.key">
    <input v-model="field.value.name" />
    <button type="button" @click="remove(index)">Remove</button>
  </div>
</template>

Full code: examples/arrays.md


Pattern 5: Server-side errors

setErrors takes a record of field names to messages, and setFieldError sets one. Both put a server's verdict where the field's own error would go, so the template needs no separate branch.

const onSubmit = handleSubmit(async (values) => {
  try {
    await createUser(values);
  } catch (error) {
    const fieldErrors = extractFieldErrors(error);
    if (fieldErrors) {
      setErrors(fieldErrors);
    } else {
      setFieldError("email", "Could not create the account");
    }
  }
});

The next validation run clears them — a server error persists only until the field it names changes, which is why a rejected submission needs the message re-set rather than remembered.


Pattern 6: Form meta

meta aggregates the fields: valid, dirty, touched and pending describe the form as a whole.

<template>
  <button :disabled="!meta.valid || !meta.dirty || isSubmitting">
    {{ isSubmitting ? "Saving..." : "Save" }}
  </button>
  <p v-if="meta.dirty">You have unsaved changes</p>
</template>

After a successful save, resetForm({ values: saved }) makes the saved data the new baseline, which is what returns meta.dirty to false.

Full code: examples/core.md Pattern 4

</patterns>

<red_flags>

Red flags

Breaks at runtime:

  • A schema handed to validationSchema without toTypedSchema() — it is accepted and then never validates, so the form submits whatever it holds.
  • props.name passed to useField instead of a getter — the field binds to the name captured at setup and ignores every later change.
  • initialValues missing a field array — the composable iterates undefined and throws.
  • An array index as the useFieldArray iteration key — Vue matches the wrong entries, so removing a middle row shifts every value below it up one.
  • resetForm(data) in place of resetForm({ values: data }) — the argument shape is wrong, and the reset takes no effect rather than reporting.

Surprising behaviour:

  • errors holds the first error per field; errorBag holds all of them as arrays. A password rule set showing one unmet requirement at a time is reading the wrong one.
  • meta.valid is false on the first render, before validation has run — a submit button gated on it alone starts disabled.
  • keepValuesOnUnmount defaults to false, so a field that unmounts loses its value. Set it true for anything that hides fields between steps.
  • Nested fields address by dot notation (defineField("user.profile.name")) and array items by brackets (errors["items[0].name"]) — the two are not interchangeable.
  • A computed schema must be passed as the computed itself, not .value — unwrapped, the form binds to one snapshot and stops tracking it.
  • validateOnValueUpdate left on validates every keystroke, including the first.
  • Errors shown without checking meta.touched appear before the user has reached the field.

Worked before/after code for the most common of these is in reference.md.

</red_flags>

리뷰

아직 리뷰가 없습니다. 사용해 본 소감을 남겨 주세요.

댓글

로그인 없이 쓸 수 있습니다. 사용 후기, 질문, 작동하지 않은 환경 등을 편하게 남겨 주세요.

아직 댓글이 없습니다. 첫 댓글을 남겨 보세요.

보내면 바로 공개됩니다. 이메일 주소나 전화번호 같은 개인 정보는 쓰지 마세요. URL은 2개까지입니다.

0 / 1,000자

이 양식은 reCAPTCHA로 보호되며 Google 개인정보처리방침 및 서비스 약관이 적용됩니다.

같은 저장소의 스킬

Hugging Face Inference SDK patterns for TypeScript/Node.js — InferenceClient setup, chat completion, text generation, streaming, embeddings, image generation, audio transcription, translation, summarization, and Inference Endpoints

한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.

agents-inc/skills252026년 10월 17일 업데이트

LiteLLM proxy server setup, TypeScript client patterns via OpenAI SDK, model routing, fallbacks, load balancing, spend tracking, virtual keys, and production deployment

한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.

agents-inc/skills252026년 10월 17일 업데이트

Serverless GPU compute platform for AI model deployment — web endpoints, GPU functions, model serving, and TypeScript client patterns

한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.

agents-inc/skills252026년 10월 17일 업데이트

Local LLM inference with the Ollama JavaScript client -- chat, streaming, tool calling, vision, embeddings, structured output, model management, and OpenAI-compatible endpoint

한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.

agents-inc/skills252026년 10월 17일 업데이트

Replicate SDK patterns for TypeScript/Node.js -- client setup, predictions, streaming, webhooks, file handling, model versioning, deployments, and training

한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.

agents-inc/skills252026년 10월 17일 업데이트

Together AI SDK patterns for TypeScript — client setup, chat completions, streaming, structured output, function calling, embeddings, image generation, fine-tuning, and OpenAI-compatible endpoints

한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.

agents-inc/skills252026년 10월 17일 업데이트

agents-inc의 스킬 모두 보기

이 스킬의 문제 신고