agentsclimarketplace

Veevalidate form validator

Skill smicolon/ai-kit/packs/nuxtjs/skills/veevalidate-form-validator

Convention packs for any AI coding tool - agents, skills, commands, and rules for 15 tools including Claude Code, Cursor, Windsurf, and Copilot

Install
npx -y skills add smicolon/ai-kit --skill veevalidate-form-validator

Assembled from the repository path, not quoted from the project. Check it against their README if it does not work.

2 things to look at

  • no licenseNo license file was found in the repository. Code published without one is not open source by default, so using it at work is a question for whoever answers licensing questions where you are.
  • 6 stars6 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.

What its author says it does

Copied from the file, not written here

This skill should be used when the user asks to "create a form", "add validation", "handle form submission", "use VeeValidate", or when creating login, signup, or data entry forms in Nuxt.js/Vue 3. Enforces VeeValidate + Zod pattern.

SKILL.md

4.5 KB, ~1.1k tokens by cl100k_base, as published. Nobody here has run it

VeeValidate + Zod Form Validator

Activation Triggers

This skill activates when:

  • Creating form components
  • Mentioning "form", "validation", "input"
  • Writing <form> or v-model
  • Handling user input

Required Pattern

<script setup lang="ts">
import { useForm } from 'vee-validate'
import { toTypedSchema } from '@vee-validate/zod'
import { z } from 'zod'

// Define schema with Zod
const schema = toTypedSchema(
  z.object({
    email: z.string().email('Invalid email'),
    password: z.string().min(8, 'Password too short'),
  })
)

// Create form with VeeValidate
const { handleSubmit, errors, defineField } = useForm({
  validationSchema: schema,
})

// Define reactive fields
const [email, emailAttrs] = defineField('email')
const [password, passwordAttrs] = defineField('password')

// Type-safe submit handler
const onSubmit = handleSubmit((values) => {
  // values is typed: { email: string, password: string }
  console.log(values.email, values.password)
})
</script>

<template>
  <form @submit="onSubmit">
    <div>
      <label for="email">Email</label>
      <input
        id="email"
        v-model="email"
        v-bind="emailAttrs"
        type="email"
        aria-describedby="email-error"
      />
      <span v-if="errors.email" id="email-error" class="error" role="alert">
        {{ errors.email }}
      </span>
    </div>

    <div>
      <label for="password">Password</label>
      <input
        id="password"
        v-model="password"
        v-bind="passwordAttrs"
        type="password"
        aria-describedby="password-error"
      />
      <span v-if="errors.password" id="password-error" class="error" role="alert">
        {{ errors.password }}
      </span>
    </div>

    <button type="submit">Submit</button>
  </form>
</template>

Forbidden Patterns

<!-- WRONG: No validation -->
<input v-model="email" />
<button @click="submit">Submit</button>

<!-- WRONG: Manual validation -->
<input v-model="email" @blur="validateEmail" />

<!-- WRONG: Template-only validation -->
<input v-model="email" :class="{ error: !isValidEmail }" />

Complex Form Example

<script setup lang="ts">
import { useForm, useFieldArray } from 'vee-validate'
import { toTypedSchema } from '@vee-validate/zod'
import { z } from 'zod'

const schema = toTypedSchema(
  z.object({
    name: z.string().min(1, 'Name required'),
    email: z.string().email(),
    role: z.enum(['admin', 'user', 'guest']),
    skills: z.array(z.object({
      name: z.string().min(1),
      level: z.number().min(1).max(5),
    })).min(1, 'At least one skill required'),
  })
)

const { handleSubmit, errors, defineField, values } = useForm({
  validationSchema: schema,
  initialValues: {
    name: '',
    email: '',
    role: 'user',
    skills: [{ name: '', level: 1 }],
  },
})

const { fields, push, remove } = useFieldArray('skills')

const [name, nameAttrs] = defineField('name')
const [email, emailAttrs] = defineField('email')
const [role, roleAttrs] = defineField('role')
</script>

Error Display Pattern

<!-- Inline errors -->
<div class="field">
  <label for="email">Email</label>
  <input
    id="email"
    v-model="email"
    v-bind="emailAttrs"
    :class="{ 'border-red-500': errors.email }"
    aria-invalid="errors.email ? 'true' : undefined"
    aria-describedby="email-error"
  />
  <Transition name="fade">
    <p v-if="errors.email" id="email-error" class="text-red-500 text-sm" role="alert">
      {{ errors.email }}
    </p>
  </Transition>
</div>

Async Validation

const schema = toTypedSchema(
  z.object({
    username: z.string()
      .min(3)
      .refine(async (val) => {
        const response = await $fetch(`/api/check-username?q=${val}`)
        return response.available
      }, 'Username already taken'),
  })
)

Validation Report

FORM VALIDATION CHECK

File: components/LoginForm.vue

 VeeValidate: useForm imported and used
 Zod schema: Defined with proper types
 Error display: Errors shown with role="alert"
 Accessibility: Labels and aria attributes present
 Type safety: Form values properly typed

Issues:
 Line 23: Missing aria-describedby on password input
 Line 34: Error message not accessible (missing role="alert")

Summary: 2 issues to fix

What ships with it

Read from the repository

Just SKILL.md. No reference files, no scripts.

Keep looking

Skills are one crate of 327,069. Ordering is by how many stacks a row turns up in, so the top of any crate is what has actually been picked rather than what has the most stars.