Search code examples
htmlwai-ariawcag2.0

WCAG 2.0 aria-labelledby for form header and disclaimer


I'm unsure on how a form is aria-labelledby or aria-describedby when you're trying to put a header and a disclaimer like "All fields are required unless marked optional" disclaimer at the top of your form. I think this is how I think it's done, but I'm new to accessibility, so any corrections would be greatly appreciated!

<form id="profile optional">
  <h1 arialabelledby="profile">Profile</h1>
  <p aria-describedby="optional">All fields are required unless marked optional</p>

  <fieldset>
    <legend id="userInfo" aria-labelledby="formA">User Info</legend>

    <div class="form-control">
      <label id="firstName" for="firstName">First Name</label>
      <input type="text" name="firstName" aria-labelledby="firstName userInfo" aria-required="true" aria-describedby="error-message"/>
      <span id="error-message" style="display:none" aria-hidden="true">Name is required</span>
    </div>

    <div class="form-control">
      <label id="lastName" for="lastName">Last Name</label>
      <input type="text" name="lastName" aria-labelledby="lastName userInfo" aria-required="true" aria-describedby="error-message"/>
      <span id="error-message" style="display:none" aria-hidden="true">Name is required</span>
    </div>

    <div class="form-control">
      <label id="nickName" for="nickName">Nick Name (optional)</label>
      <input type="text" name="nickName" aria-labelledby="nickName userInfo"/>
    </div>
  <fieldset>

  <fieldset>
  ...
  </fieldset>

  <button type="submit" aria-label="Submit Profile">Submit</button>
</form>

Edit* code for submit button


Solution

  • This is a case where you do not need any ARIA. You can fall back to good UX and it will make the ARIA unnecessary.

    At the start of your form you provide instructions that all fields are required. That is good. Then for fields that are option you include "(optional)" in the <label>. That is also good.

    You could stop there and be all set.

    However, you have added ARIA into the form and gotten some of it backwards. For example:

    <form id="profile optional">
     <h1 arialabelledby="profile">Profile</h1>
     <p aria-describedby="optional">All fields are required unless marked optional</p>
    

    You are telling the <h1> that is labeled by the <form> when it should be the other way around. You are also telling the <p> that it is being described by the <form>, which again would be the other way around. Just yank all that out.

    Or take this case:

    <div class="form-control">
      <label id="lastName" for="lastName">Last Name</label>
      <input type="text" name="lastName" aria-labelledby="lastName userInfo" aria-required="true" aria-describedby="error-message"/>
      <span id="error-message" style="display:none" aria-hidden="true">Name is required</span>
    </div>
    

    The <input> does not need aria-labelledby<label> does that for free. Additionally associating it with the <legend> makes it more verbose and can confuse users.

    You should also remove aria-required and just use the HTML5 boolean required. It is well supported and benefits non-screen-reader users.

    While I suspect you are only going to show the error message if there is an error, you can remove it altogether and let the browser handle it. If you need to keep it for backward compat, then drop the aria-hidden since the display:none hides it from screen readers anyway.

    Same goes for the button. Dump the ARIA and just make it <button type="submit">Submit Profile</button>. All your users will benefit from the more verbose button.

    Since you make good use of <legend> and <fieldset>, you can leave all that stuff and you are in good shape.

    You will have just created an accessible, usable, ARIA-free form. ARIA-free is a good thing. ARIA is a bridging technology that should only be used when there is no affordance in regular HTML.