next-js/skills/skills/form-builder/SKILL.md
Build forms using React Hook Form with Yup validation, following the project's HookForm component system and Field components. Use this skill whenever the user needs to create a form (contact, settings, login, data entry, filters, any form), add form validation, use the project's Field/HookForm components, create filter forms, or build any data input interface. Also trigger when the user mentions "form", "validation", "Yup schema", "fields", "input fields", "form submission", or wants to collect user data through a UI.
npx skillsauth add spuneiartur/claude-agent-specs form-builderInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
Build forms using the project's React Hook Form + Yup validation system. This project has a complete form infrastructure — use it instead of building forms from scratch.
The form system has three layers:
models/{name}.js) — Yup schema + initial values@components/HookForm) — Connects React Hook Form with Yup resolver@components/Fields) — Pre-built input components with error displayCreate models/{form-name}.js with two named exports:
import * as Yup from 'yup';
export const validationSchema = Yup.object().shape({
name: Yup.string().required('Name is required'),
email: Yup.string().email('Invalid email').required('Email is required'),
status: Yup.string().oneOf(['active', 'inactive']).required(),
description: Yup.string(),
image: Yup.object().nullable(),
items: Yup.array().of(
Yup.object().shape({
title: Yup.string().required(),
value: Yup.mixed().required(),
})
),
});
export const initialValues = {
name: '',
email: '',
status: 'active',
description: '',
image: null,
items: [],
};
Every field in validationSchema must have a matching key in initialValues.
For filter forms, create models/{entity}-filters.js — all fields are optional strings:
import * as Yup from 'yup';
export const validationSchema = Yup.object().shape({
search: Yup.string(),
status: Yup.string(),
created_from: Yup.string(),
created_to: Yup.string(),
});
export const initialValues = { search: '', status: '', created_from: '', created_to: '' };
import { create{Entity} } from '@api/{entity}';
import { Button } from '@components';
import { Form, HookForm, Submit } from '@components/HookForm';
import { useMutation } from '@hooks';
import { initialValues, validationSchema } from '@models/{entity}';
import { useRouter } from 'next/router';
const Add{Entity}Form = () => {
const router = useRouter();
const mutation = useMutation(create{Entity}, {
invalidateQueries: 'admin/{entities}',
successCallback: () => router.push('/admin/{entities}'),
});
const handleSubmit = async (data) => mutation.mutateAsync(data);
return (
<HookForm initialValues={initialValues} validationSchema={validationSchema} onSubmit={handleSubmit}>
<Form>
{/* Form fields go here (see Step 3) */}
<Submit disabled={mutation.isPending}>
{mutation.isPending ? 'Saving...' : 'Save'}
</Submit>
</Form>
</HookForm>
);
};
import { Search, Dropdown, DatePicker } from '@components/Fields';
import { Field } from '@components/HookForm';
import AutoSubmitFilterForm from '@components/HookForm/AutoSubmitFilterForm';
import { initialValues, validationSchema } from '@models/{entity}-filters';
const Filters = ({ setOptions }) => (
<AutoSubmitFilterForm initialValues={initialValues} validationSchema={validationSchema} onSubmit={setOptions}>
<div className="grid grid-cols-1 gap-4 md:grid-cols-2 lg:grid-cols-3">
<Field as={Search} name="search" placeholder="Search..." label="Search" />
<Field as={Dropdown} name="status" label="Status">
<option value="">All</option>
<option value="active">Active</option>
</Field>
<Field as={DatePicker} name="created_from" label="From date" />
</div>
</AutoSubmitFilterForm>
);
Same as the standard form, but pass the entity object as initialValues:
const EditForm = ({ entity }) => (
<HookForm initialValues={entity} validationSchema={validationSchema} onSubmit={handleSubmit}>
...
</HookForm>
);
The <Field> component renders any field type via the as prop:
<Field as={Input} name="title" label="Title" placeholder="Enter title" required />
Import from @components/Fields:
| Component | Use For |
|-----------|---------|
| Input | Text, generic input |
| Email | Email with validation styling |
| Password | Password with toggle visibility |
| Phone | Phone number |
| Number | Numeric input |
| Textarea | Multi-line text |
| RichText | Rich text editor (React Quill) |
| Dropdown | Select with <option> children |
| Search | Search input with debounce |
| DatePicker | Date selection |
| TimePicker | Time selection |
| DateOfBirth | Date of birth (day/month/year dropdowns) |
| Checkbox | Single checkbox |
| Toggle | Toggle switch |
| Radio | Radio button (use within RadioGroup) |
| RadioGroup | Group of radio buttons |
| Select | Custom select |
| LabeledSelect | Select with label |
| Combobox | Searchable dropdown |
| AsyncCombobox | Searchable dropdown with async data |
| ComboboxWithImage | Combobox with image previews |
| AsyncComboboxWithImage | Async combobox with images |
| Autocomplete | Autocomplete text input |
| AutocompleteWithImage | Autocomplete with images |
| MultiSelectAsync | Multi-select with async options |
| AsyncDropdown | Dropdown loaded from API |
| SlugInput | URL slug auto-generated from another field |
| FileDrop | Drag-and-drop file upload |
| FileUpload | File upload button |
| Embed | Embed URL input |
| PlusMinus | Increment/decrement number |
| Recaptcha | Google reCAPTCHA |
SlugInput — Auto-generates URL slug from a source field:
<SlugInput sourceField="title" placeholder="url-slug" required />
ArrayField — Dynamic repeatable sections:
import { ArrayField } from '@components/HookForm';
<ArrayField
name="sections"
AddComponent={AddButton}
SectionComponent={SectionRenderer}
emptyRow={{ type: 'text', content: '', timestamp: Date.now() }}
/>
Fieldset — Group fields with a label:
import { Fieldset } from '@components/HookForm';
<Fieldset legend="Contact Info">...</Fieldset>
Use useFormContext() from react-hook-form to access form state in child components:
import { useFormContext } from 'react-hook-form';
const NestedComponent = () => {
const { formState, watch, setValue } = useFormContext();
const status = watch('status');
// ...
};
| What | Import From |
|------|------------|
| HookForm, Form, Submit, Field, ArrayField, Fieldset | @components/HookForm |
| AutoSubmitFilterForm | @components/HookForm/AutoSubmitFilterForm |
| All field components | @components/Fields |
| useMutation | @hooks |
| useFormContext | react-hook-form |
| Yup | yup |
tools
Replace with description of the skill and when Claude should use it.
tools
Comprehensive website performance audit and optimization skill. Identifies and automatically fixes performance issues including image optimization, video compression, lazy loading, Core Web Vitals, bundle size, and rendering strategy. Uses Lighthouse (via CLI or MCP when available), ffmpeg for media processing, and the project's existing Image component with blur-up lazy loading. Use this skill whenever the user mentions: website speed, page load time, performance audit, Core Web Vitals, Lighthouse, optimize images, compress videos, lazy loading, LCP, CLS, FID, INP, slow website, speed up, performance optimization, image compression, video optimization, blur placeholder, WebP conversion, media audit, bundle size, or wants to improve their website's loading performance. Also trigger when the user says "my site is slow", "optimize for speed", "reduce load time", "improve performance", or asks about image/video optimization in any context.
tools
Toolkit for interacting with and testing local web applications using Playwright. Supports verifying frontend functionality, debugging UI behavior, capturing browser screenshots, and viewing browser logs.
tools
Suite of tools for creating elaborate, multi-component claude.ai HTML artifacts using modern frontend web technologies (React, Tailwind CSS, shadcn/ui). Use for complex artifacts requiring state management, routing, or shadcn/ui components - not for simple single-file HTML/JSX artifacts.