<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Ilknur Eren</title>
    <description>The latest articles on DEV Community by Ilknur Eren (@ilknur).</description>
    <link>https://dev.to/ilknur</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4018541%2F94961991-50e3-46fd-ae59-57bfa731550e.jpg</url>
      <title>DEV Community: Ilknur Eren</title>
      <link>https://dev.to/ilknur</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/ilknur"/>
    <language>en</language>
    <item>
      <title>Accessible Form Labels</title>
      <dc:creator>Ilknur Eren</dc:creator>
      <pubDate>Sat, 11 Jul 2026 00:00:15 +0000</pubDate>
      <link>https://dev.to/ilknur/accessible-form-labels-5fpl</link>
      <guid>https://dev.to/ilknur/accessible-form-labels-5fpl</guid>
      <description>&lt;p&gt;Labels are a foundational part of any accessible form. Without properly implemented, users who rely on screen readers have no way to understand what a field is asking for. A label does two things: it tells the user what a field is for, and it connects that meaning to the input in the code so assistive technology can announce it. There are a number of basic form label accessibility rules all developers should follow to build accessible forms. &lt;/p&gt;

&lt;h2&gt;
  
  
  Use the &lt;code&gt;&amp;lt;label&amp;gt;&lt;/code&gt; element
&lt;/h2&gt;

&lt;p&gt;Every input needs a visible, programmatic label. The most reliable way to label an input is with the HTML  element, linked to the input using matching for and id attributes. Example is below:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;label&lt;/span&gt; &lt;span class="na"&gt;for=&lt;/span&gt;&lt;span class="s"&gt;"email"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Email address&lt;span class="nt"&gt;&amp;lt;/label&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;input&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"email"&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"email"&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"email"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the example above, the first line is the label of the form field. With the proper for and id, we can programmatically link the  tag to the  tag. Additionally to linking the label, when the for and id values match, clicking or tapping the label text also moves focus to the input. &lt;/p&gt;

&lt;h2&gt;
  
  
  When a visible label isn't practical
&lt;/h2&gt;

&lt;p&gt;Some designs use a search bar with a button, or a compact inline form, where a visible label would feel visually cluttered. In those cases, use aria-label or aria-labelledby to provide a label programmatically without showing it visually.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="c"&gt;&amp;lt;!-- aria-label: attach a label string directly to the input --&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;input&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"search"&lt;/span&gt; &lt;span class="na"&gt;aria-label=&lt;/span&gt;&lt;span class="s"&gt;"Search the site"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="c"&gt;&amp;lt;!-- aria-labelledby: point to an existing element on the page by its id --&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;h2&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"signup-heading"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Create your account&lt;span class="nt"&gt;&amp;lt;/h2&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;input&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"email"&lt;/span&gt; &lt;span class="na"&gt;aria-labelledby=&lt;/span&gt;&lt;span class="s"&gt;"signup-heading"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Use &lt;code&gt;aria-labelledby&lt;/code&gt; when label text already exists on the page. It references that text by id, so screen readers announce it without duplication.&lt;/p&gt;

&lt;h2&gt;
  
  
  Placeholder text is not a label
&lt;/h2&gt;

&lt;p&gt;This is one of the most common labeling mistakes. Placeholder text disappears the moment someone starts typing, screen readers don't reliably announce it as label text, and its low contrast often fails WCAG minimums. It can hint at expected format (like "MM/DD/YYYY"), but it must never stand in for a real label.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="c"&gt;&amp;lt;!-- Wrong: no label, placeholder only --&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;input&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"text"&lt;/span&gt; &lt;span class="na"&gt;placeholder=&lt;/span&gt;&lt;span class="s"&gt;"Full name"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="c"&gt;&amp;lt;!-- Right: visible label + placeholder as a format hint --&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;label&lt;/span&gt; &lt;span class="na"&gt;for=&lt;/span&gt;&lt;span class="s"&gt;"dob"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Date of birth&lt;span class="nt"&gt;&amp;lt;/label&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;input&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"text"&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"dob"&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"dob"&lt;/span&gt; &lt;span class="na"&gt;placeholder=&lt;/span&gt;&lt;span class="s"&gt;"MM/DD/YYYY"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Marking required fields
&lt;/h2&gt;

&lt;p&gt;If a field is required, mark it in two ways: in the code and in the visible label.&lt;br&gt;
Add &lt;code&gt;required&lt;/code&gt; (or &lt;code&gt;aria-required="true"&lt;/code&gt;) to the input so assistive technology announces it. Then add visible text — like "(required)" — next to the label so sighted users also see it.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;label&lt;/span&gt; &lt;span class="na"&gt;for=&lt;/span&gt;&lt;span class="s"&gt;"name"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Full name (required)&lt;span class="nt"&gt;&amp;lt;/label&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;input&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"text"&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"name"&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"name"&lt;/span&gt; &lt;span class="na"&gt;required&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A red asterisk alone is not sufficient. Screen readers may not announce it, sighted users may not know what it means without a legend, and color alone never conveys meaning in an accessible way. If you do use an asterisk, include a visible legend near the top of the form — for example, "Fields marked with * are required" — and wrap the asterisk in &lt;span&gt; so screen readers skip it and rely on the required attribute instead.&lt;br&gt;
&lt;/span&gt;&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;p&amp;gt;&lt;/span&gt;Fields marked with &lt;span class="nt"&gt;&amp;lt;span&lt;/span&gt; &lt;span class="na"&gt;aria-hidden=&lt;/span&gt;&lt;span class="s"&gt;"true"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;*&lt;span class="nt"&gt;&amp;lt;/span&amp;gt;&lt;/span&gt; are required.&lt;span class="nt"&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;label&lt;/span&gt; &lt;span class="na"&gt;for=&lt;/span&gt;&lt;span class="s"&gt;"phone"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Phone number &lt;span class="nt"&gt;&amp;lt;span&lt;/span&gt; &lt;span class="na"&gt;aria-hidden=&lt;/span&gt;&lt;span class="s"&gt;"true"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;*&lt;span class="nt"&gt;&amp;lt;/span&amp;gt;&amp;lt;/label&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;input&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"tel"&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"phone"&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"phone"&lt;/span&gt; &lt;span class="na"&gt;required&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h2&gt;
  
  
  Keep labels close to their inputs
&lt;/h2&gt;

&lt;p&gt;Sighted users scan forms by proximity. Labels should appear directly above or immediately to the left of their input, not below and not far away. This also helps users who zoom in on a page, since distant labels may scroll out of view.&lt;/p&gt;
&lt;h2&gt;
  
  
  Label groups of related inputs
&lt;/h2&gt;

&lt;p&gt;For radio buttons, checkboxes, and other grouped inputs, use&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;fieldset&amp;gt;&lt;/span&gt; and &lt;span class="nt"&gt;&amp;lt;legend&amp;gt;&lt;/span&gt; to label the group as a whole. Each individual option still needs its own &lt;span class="nt"&gt;&amp;lt;label&amp;gt;&lt;/span&gt;.
html
&lt;span class="nt"&gt;&amp;lt;fieldset&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;legend&amp;gt;&lt;/span&gt;Preferred contact method&lt;span class="nt"&gt;&amp;lt;/legend&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;input&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"radio"&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"contact-email"&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"contact"&lt;/span&gt; &lt;span class="na"&gt;value=&lt;/span&gt;&lt;span class="s"&gt;"email"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;label&lt;/span&gt; &lt;span class="na"&gt;for=&lt;/span&gt;&lt;span class="s"&gt;"contact-email"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Email&lt;span class="nt"&gt;&amp;lt;/label&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;input&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"radio"&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"contact-phone"&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"contact"&lt;/span&gt; &lt;span class="na"&gt;value=&lt;/span&gt;&lt;span class="s"&gt;"phone"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;label&lt;/span&gt; &lt;span class="na"&gt;for=&lt;/span&gt;&lt;span class="s"&gt;"contact-phone"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Phone&lt;span class="nt"&gt;&amp;lt;/label&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/fieldset&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Without &lt;code&gt;&amp;lt;fieldset&amp;gt;&lt;/code&gt; and &lt;code&gt;&amp;lt;legend&lt;/code&gt;&amp;gt;, a screen reader user hears "Email, radio button" with no context about what they're choosing.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Accessible forms are not an edge case or a nice-to-have, they are a baseline requirement. The labeling practices covered in this article are some of the most impactful changes you can make, because labels are the foundation everything else builds on. A form without proper labels fails before a user even has a chance to fill it out.&lt;/p&gt;

</description>
      <category>a11y</category>
      <category>beginners</category>
      <category>html</category>
      <category>webdev</category>
    </item>
  </channel>
</rss>
