skills/form-builder/SKILL.md
Build contact, lead capture, and booking forms that save submissions to Supabase. Uses react-hook-form + zod validation. Vietnamese field labels and error messages. Activated by vibe and vibe-add for any form feature request.
npx skillsauth add Hikkywannafly/vibe-kit 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.
Generate production-ready forms with client-side validation, server-side submission to Supabase, and Vietnamese error messages. No third-party form services needed.
npm install react-hook-form @hookform/resolvers zod
shadcn/ui Form components required (see shadcn-ui skill).
// components/contact-form.tsx
"use client"
import { useForm } from "react-hook-form"
import { zodResolver } from "@hookform/resolvers/zod"
import { z } from "zod"
import { useState } from "react"
import { createClient } from "@/lib/supabase/client"
import { Button } from "@/components/ui/button"
import { Input } from "@/components/ui/input"
import { Textarea } from "@/components/ui/textarea"
import { toast } from "sonner"
const schema = z.object({
name: z.string().min(2, "Ten phai co it nhat 2 ky tu"),
phone: z.string().regex(/^(0|\+84)[0-9]{9}$/, "So dien thoai khong hop le"),
email: z.string().email("Email khong dung dinh dang").optional().or(z.literal("")),
message: z.string().min(10, "Tin nhan qua ngan, viet them nhe"),
})
type FormData = z.infer<typeof schema>
export function ContactForm() {
const [loading, setLoading] = useState(false)
const form = useForm<FormData>({ resolver: zodResolver(schema) })
async function onSubmit(data: FormData) {
setLoading(true)
const supabase = createClient()
const { error } = await supabase.from("contact_submissions").insert([data])
if (error) {
toast.error("Co loi xay ra. Vui long thu lai sau.")
} else {
toast.success("Da gui thanh cong! Chung toi se lien he ban som.")
form.reset()
}
setLoading(false)
}
return (
<form onSubmit={form.handleSubmit(onSubmit)} className="space-y-4 max-w-md">
<div>
<label className="text-sm font-medium">Ho ten *</label>
<Input {...form.register("name")} placeholder="Nguyen Van A" />
{form.formState.errors.name && (
<p className="text-sm text-red-500 mt-1">{form.formState.errors.name.message}</p>
)}
</div>
<div>
<label className="text-sm font-medium">So dien thoai *</label>
<Input {...form.register("phone")} placeholder="0901234567" />
{form.formState.errors.phone && (
<p className="text-sm text-red-500 mt-1">{form.formState.errors.phone.message}</p>
)}
</div>
<div>
<label className="text-sm font-medium">Tin nhan *</label>
<Textarea {...form.register("message")} placeholder="Ban muon hoi gi?" rows={4} />
{form.formState.errors.message && (
<p className="text-sm text-red-500 mt-1">{form.formState.errors.message.message}</p>
)}
</div>
<Button type="submit" disabled={loading} className="w-full">
{loading ? "Dang gui..." : "Gui tin nhan"}
</Button>
</form>
)
}
create table if not exists public.contact_submissions (
id uuid primary key default gen_random_uuid(),
name text not null,
phone text not null,
email text,
message text not null,
created_at timestamptz default now()
);
alter table public.contact_submissions enable row level security;
-- Allow inserts from anyone (public contact form)
create policy "contact_insert" on public.contact_submissions
for insert with check (true);
-- Only service role / admin can read
create policy "contact_admin_read" on public.contact_submissions
for select using (false);
| Form type | Fields | Table |
|-----------|--------|-------|
| Lead capture | email, name | leads |
| Booking | name, phone, date, service | bookings |
| Order | name, phone, address, items | orders |
| Survey | dynamic fields | survey_responses |
data-ai
Generate Vietnamese marketing copy, UI strings, CTAs, error messages, and email templates for vibe-kit projects. Tone: friendly, conversational, Southern Vietnamese style. Activated for any user-visible text generation.
development
One-shot orchestrator. Turns the prose after /vibe into a shipped product by clarifying intent, rendering a plan, gating on approval, then spawning planner+researcher+fullstack-dev+tester+reviewer agents in sequence. User-visible strings match the user's input language (Vietnamese by default for VN users). Two modes: SAFE (default — clarify + show plan + wait for approval, max 1 round-trip) and YOLO (skip clarify+approval, run full auto with smart defaults — for demos and power users). YOLO triggers: prose contains `yolo`, `nhanh nha`, `lam luon`, `khoi hoi`, `auto`, or args start with `yolo`. Trigger phrases (EN + VN): "build me a site", "make me a landing page", "create a shop", "I need an app", "vibe lam website", "tao cho toi mot", "xay dung shop online", "lam landing page", "can mot app".
tools
On-demand security audit for vibe-kit projects. Stack-aware checks for Next.js App Router + Supabase + Polar: secrets leak, RLS gaps, service-role key in client bundle, missing webhook signature verification, unprotected API routes, weak headers, dependency vulns. Outputs a Vietnamese P0/P1/P2 report with file:line + fix hints. User-visible strings match the user's input language (Vietnamese by default for VN users). Trigger phrases (EN + VN): "check security", "audit it", "security scan", "is this safe to launch", "kiem tra bao mat", "quet bao mat", "audit du an", "co an toan khong", "scan bao mat truoc khi deploy".
tools
Wire Supabase JS client into a React Native (Expo) vibe-kit project: session persistence via AsyncStorage, magic-link OAuth callback via expo-linking deep links, Realtime subscriptions on RN, and shared TypeScript types with the Next.js webapp twin (vibe-kit's typical web<->mobile pair pattern). This is the mobile counterpart of `auth-magic-link` (web). User-visible strings match the user's input language (Vietnamese by default for VN users). Trigger phrases (EN + VN): "supabase react native", "supabase mobile", "auth mobile expo", "magic link mobile", "tich hop supabase vao app", "supabase deep link".