This episode breaks down form accessibility: correct labels with the for attribute, grouping controls with fieldset and legend, and why placeholder does not replace a label.

In episode 8 you wrote forms with improvised labels. Episode 9 fixes that: labels, fieldsets, and form accessibility. An accessible form isn't just a nice-to-have — without correct labels, screen reader users can't know what they're supposed to fill in.
This episode covers two fundamental patterns: connecting a label to a control via the for and id attributes, and grouping related choices with fieldset and legend. Both are the foundation of good validation and form UX.
The label element gives a name to a control. The relationship is formed by matching the for on the label with the id on the control:
<p>
<label for="nama-lengkap">Nama lengkap</label>
<input type="text" id="nama-lengkap" name="nama">
</p>When a label is correctly connected, clicking the label text moves focus to the input. Screen readers announce the label when the control receives focus — users know exactly what's being asked.
Another alternative: wrap the control inside the label without attributes:
<label>
Nama lengkap
<input type="text" name="nama">
</label>This pattern is shorter and still creates an implicit relationship. Both are valid; what matters is that every control has an accessible label.
fieldset groups related controls, and legend gives the group a title:
<fieldset>
<legend>Alamat pengiriman</legend>
<p>
<label for="jalan">Jalan</label>
<input type="text" id="jalan" name="jalan">
</p>
<p>
<label for="kota">Kota</label>
<input type="text" id="kota" name="kota">
</p>
</fieldset>legend is announced by screen readers as the group's title — users know the controls inside form one unit.
Radio and checkbox groups almost always use fieldset:
<fieldset>
<legend>Ukuran paket</legend>
<label>
<input type="radio" name="ukuran" value="kecil">
Kecil
</label>
<label>
<input type="radio" name="ukuran" value="besar">
Besar
</label>
</fieldset>Without fieldset, screen reader users hear a series of radio options without knowing what the question is. legend answers that.
The most common mistake: using placeholder as the only explanation and writing the label somewhere off-screen. The problems: the placeholder disappears as soon as the user starts typing, its color has low contrast, and some screen readers don't announce it as the control's name.
<p>
<label for="email">Alamat email</label>
<input
type="email"
id="email"
name="email"
placeholder="nama@contoh.id"
>
</p>The correct pattern: label as the permanent description, placeholder only as an additional example whose format is already clear.
Combine all the patterns into one form:
<!DOCTYPE html>
<html lang="id">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Formulir Profil</title>
</head>
<body>
<h1>Formulir Profil</h1>
<form action="/profil" method="post">
<fieldset>
<legend>Data pribadi</legend>
<p>
<label for="nama">Nama lengkap</label>
<input type="text" id="nama" name="nama">
</p>
<p>
<label for="email">Alamat email</label>
<input type="email" id="email" name="email">
</p>
</fieldset>
<fieldset>
<legend>Preferensi berlangganan</legend>
<label>
<input type="checkbox" name="berita" value="ya">
Kirim berita mingguan
</label>
<label>
<input type="checkbox" name="promo" value="ya">
Kirim promo terbaru
</label>
</fieldset>
<p>
<button type="submit">Simpan Profil</button>
</p>
</form>
</body>
</html>Open the page and use the Tab key to move between controls. In the console, inspect the connected labels with document.getElementById("nama").labels — the result should contain the correct label element.
A for on label that doesn't match any id breaks the relationship. Make sure both values are exactly identical and unique within the page.
A fieldset for one single control isn't needed and creates a strange hierarchy. Use it only for groups of related controls.
Episode 9 makes your forms accessible: label with for and id, fieldset with legend for grouping, and the awareness that placeholder never replaces a label.
Key takeaways:
label connected via for and id.fieldset and legend group related controls.fieldset.placeholder is just an example; label is the permanent description.for and id must match exactly and be unique.In the next episode, episode 10, we'll cover basic content accessibility — ARIA attributes, alternative text, and keyboard focus. You'll learn to create content accessible to everyone, including assistive technology users.