1import { useFieldArray, useForm } from 'react-hook-form';
2import { HiOutlineMinusCircle, HiOutlinePlusCircle } from 'react-icons/hi';
3
4const DynamicForm = () => {
5 const {
6 register,
7 control,
8 watch,
9 formState: { errors },
10 } = useForm({
11 defaultValues: {
12 title: '',
13 tags: [
14 {
15 value: '',
16 },
17 ],
18 },
19 });
20
21 const { fields, insert, remove } = useFieldArray({
22 control,
23 name: 'tags',
24 });
25
26 return (
27 <div className="grid grid-cols-1 lg:grid-cols-2">
28 <form>
29 <h2 className="mb-2">タイトル</h2>
30 <input
31 type="text"
32 autoComplete="off"
33 className="bg-transparent rounded border mb-6"
34 {...register('title')}
35 />
36 <h2 className="mb-2">タグ</h2>
37 <div className="space-y-2">
38 {fields.map((field, index) => (
39 <div key={field.id}>
40 <div className="flex items-center space-x-2">
41 <input
42 className="bg-transparent rounded border"
43 type="text"
44 autoComplete="off"
45 {...register(`tags.${index}.value`, {
46 required: '必須入力です',
47 maxLength: {
48 value: 80,
49 message: '最大80文字です',
50 },
51 })}
52 />
53 {fields.length > 1 && (
54 <button type="button" onClick={() => remove(index)}>
55 <HiOutlineMinusCircle className="text-xl opacity-60" />
56 </button>
57 )}
58 <button
59 onClick={() =>
60 insert(index + 1, {
61 value: '',
62 })
63 }
64 type="button"
65 >
66 <HiOutlinePlusCircle className="text-xl opacity-60" />
67 </button>
68 </div>
69 {errors.tags?.[index]?.value && (
70 <p className="text-red-500 text-sm">
71 {errors.tags?.[index]?.value?.message}
72 </p>
73 )}
74 </div>
75 ))}
76 </div>
77 </form>
78 <div>
79 <pre>{JSON.stringify(watch(), null, 2)}</pre>
80 </div>
81 </div>
82 );
83};
84
85export default DynamicForm;