Communitygithub.com

sakilanwar12/nextjs-typescript-skills

用於使用 react-hook-form 和 zod 建構表單 — 基於 Schema 的驗證、型別化欄位、伺服器動作提交、無障礙錯誤提示及檔案輸入。

nextjs-typescript-skills 是什麼?

此技能提供使用 react-hook-form 與 zod 建構型別安全且無障礙的表單之標準模式。它強制執行「Schema 優先」的方法,意即在 zod 中定義單一驗證規則來源,並透過 `z.infer` 推導表單值的 TypeScript 型別,確保客戶端與伺服器間的型別一致性。此模式使用 `@hookform/resolvers/zod` 的 `zodResolver`,搭配 `onTouched` 模式以提供更佳的使用者體驗,同時也包含伺服器端的重新驗證邏輯。它也涵蓋了無障礙最佳實踐,例如在輸入欄位上使用 `aria-invalid` 與 `aria-describedby`,並為錯誤訊息新增 `role="alert"`。此技能適用於 Next.js 專案,核心模式涵蓋了基本的文字與密碼輸入,但可擴展至檔案上傳及其他複雜的欄位類型。其目標為減少樣板程式碼,並防止因型別不一致或驗證邏輯重複所導致的常見錯誤。

相容平台~Claude Code~Codex CLI~Cursor
npx skills add https://github.com/sakilanwar12/nextjs-typescript-skills/tree/HEAD/skills/nextjs-forms

在你喜歡的 AI 中提問

開啟一個已預先載入此 Agent Skill 的新對話。

說明文件

表單 (react-hook-form + zod)

規則

  1. Schema 優先:定義 zod schema,透過 z.infer 推導型別。由客戶端與伺服器共享的單一事實來源。
  2. 使用 @hookform/resolvers/zod (zodResolver)。模式設為 onTouched 以獲得較佳 UX;在 action 中於伺服器端再次驗證。
  3. 為表單加上型別:useForm<FormValues>。不使用 any 作為欄位值。
  4. 無障礙錯誤提示:在訊息上使用 aria-invalid、aria-describedby、role="alert"。將 <label htmlFor> 與對應輸入關聯。
  5. 透過伺服器動作提交(使用 formAction 或呼叫伺服器函數的 action)。顯示 pending 狀態及伺服器錯誤狀態。

模式

'use client';
import { useForm } from 'react-hook-form';
import { zodResolver } from '@hookform/resolvers/zod';
import { z } from 'zod';

const Schema = z.object({
  email: z.string().email('請輸入有效的電子郵件'),
  password: z.string().min(8, '至少 8 個字元'),
});
type Values = z.infer<typeof Schema>;

export function LoginForm({ onSubmit }: { onSubmit: (v: Values) => Promise<{ ok: boolean; error?: string }> }) {
  const { register, handleSubmit, formState: { errors, isSubmitting }, setError } = useForm<Values>({
    resolver: zodResolver(Schema),
    mode: 'onTouched',
  });

  return (
    <form onSubmit={handleSubmit(async (v) => {
      const r = await onSubmit(v);
      if (!r.ok) setError('root', { message: r.error ?? '失敗' });
    })}>
      <label htmlFor="email">電子郵件</label>
      <input id="email" type="email" autoComplete="email"
        aria-invalid={!!errors.email} aria-describedby={errors.email ? 'email-err' : undefined}
        {...register('email')} />
      {errors.email && <p id="email-err" role="alert">{errors.email.message}</p>}

      <label htmlFor="password">密碼</label>
      <input id="password" type="password" autoComplete="current-password" {...register('password')} />
      {errors.password && <p role="alert">{errors.password.message}</p>}

      {errors.root && <p role="alert">{errors.root.message}</p>}
      <button disabled={isSubmitting}>{isSubmitting ? '登入中…' : '登入'}</button>
    </form>
  );
}

檢查清單

  • zod schema 加上 z.infer 型別?
  • 已連接 zodResolver?
  • 每個欄位都有標籤與 aria 屬性?
  • 伺服器端重新驗證同一個 schema?
  • 顯示 pending 禁用狀態及根層級/伺服器錯誤?

Individual skills in this repo

This repo contains 4 individual skills — each has its own dedicated page.

相關技能