Reusable Form Field Pattern
Menyusun label, input, hint, dan error menjadi pola form field yang konsisten sekaligus mudah diakses.
Tujuan belajar
- Menjelaskan bagian accessibility yang perlu konsisten pada form field
- Membuat FormField sebagai wrapper layout yang jelas
- Menghubungkan input dengan label, hint, dan error yang relevan
Isi lesson
5 blok- 1.Pengulangan form biasanya membawa aturan yang samaBelum selesaiWajib
- 2.FormField menjaga hubungan label, hint, dan errorBelum selesaiWajib
- 3.Wrapper visual saja belum cukupBelum selesaiWajib
- 4.Coding practiceBelum selesaiWajib
- 5.RingkasanBelum selesaiWajib
Pengulangan form biasanya membawa aturan yang sama
WajibForm field sering mengulang struktur yang sama: label, control, hint, dan pesan error. Pengulangan ini bukan hanya soal spacing. Label harus menunjuk input yang tepat, hint dan error perlu memiliki id yang bisa dirujuk, dan error perlu muncul dengan cara yang dapat dipahami user.
FormField di module ini adalah layout wrapper kecil. Ia tidak mencoba menangani semua jenis input, validasi server, mask, atau library form. Input tetap dimasukkan lewat children sehingga component ini dapat dipakai untuk text input, textarea, atau select tanpa API generik yang sulit dibaca.
Bagian ini memengaruhi progres lesson.
FormField menjaga hubungan label, hint, dan error
Wajibimport { useState, type ReactNode } from "react";
type FormFieldProps = {
id: string;
label: string;
hint?: string;
error?: string;
children: ReactNode;
};
function FormField({ id, label, hint, error, children }: FormFieldProps) {
return (
<div>
<label htmlFor={id}>{label}</label>
{children}
{hint ? <p id={id + "-hint"}>{hint}</p> : null}
{error ? <p id={id + "-error"} role="alert">{error}</p> : null}
</div>
);
}
export function ProfileForm() {
const [displayName, setDisplayName] = useState("Rina");
const error = displayName.trim().length < 3 ? "Nama tampilan minimal 3 karakter." : "";
const describedBy = error
? "display-name-hint display-name-error"
: "display-name-hint";
return (
<form>
<FormField
id="display-name"
label="Nama tampilan"
hint="Nama ini terlihat pada profile kamu."
error={error}
>
<input
id="display-name"
value={displayName}
aria-describedby={describedBy}
aria-invalid={Boolean(error)}
onChange={(event) => setDisplayName(event.target.value)}
/>
</FormField>
</form>
);
}FormField membuat label dan pesan pendukung pada tempat yang konsisten. Input tetap dimiliki ProfileForm karena nilai, validasi, dan aria-describedby bergantung pada state form saat itu. Jangan membuat FormField mengambil alih seluruh state semua input hanya karena markup label berulang.
Bagian ini memengaruhi progres lesson.
Kesalahan umum
WajibWrapper visual saja belum cukup
Jangan menyebut component sebagai FormField jika ia hanya menambah border lalu melupakan htmlFor, id, hint, atau error relationship. Reusability yang baik menjaga aturan yang mudah terlupa, bukan hanya memindahkan div ke file lain.
Bagian ini memengaruhi progres lesson.
Coding practice
WajibDibuka di workspace khususBuild accessible profile form field
Buat FormField kecil yang menjaga label, hint, error, dan input profile tetap terhubung saat user mengubah nama tampilan.
Tujuan awal: Fokus di tab TSX.
Practice ini dibuka di workspace khusus. Buka practice untuk memakai editor, preview, dan cek otomatis.
Tombol selesai aktif setelah semua validasi wajib lolos.
Ringkasan
Wajib- FormField dapat menyatukan markup label, hint, dan error yang berulang.
- Input tetap menerima id, aria-describedby, dan aria-invalid sesuai state form saat ini.
- Abstraction yang baik melindungi aturan accessibility yang mudah terlewat.
- Berikutnya, kamu akan memilih kapan pola seperti ini membantu dan kapan component sederhana lebih baik dibiarkan lokal.
Bagian ini memengaruhi progres lesson.
Langkah berikutnya
Selesaikan bagian penting lesson ini
Lanjutkan blok wajib berikutnya: Pengulangan form biasanya membawa aturan yang sama.