WGU D276 practice

HTML Form Validation and Accessibility: required, pattern, type, labels, fieldset, and ARIA

Built-in HTML validation and accessible labeling are two halves of the same job. Learn exactly how required, pattern, and type constraints fire, why an empty field usually passes, how label association really works, and where fieldset, legend, and ARIA attributes belong — then test yourself with explained practice questions.

What form validation and accessibility actually do

HTML form validation and accessible labeling are two halves of the same job. Validation attributes such as required, pattern, and type tell the browser what counts as acceptable input, and a correctly associated <label> tells every user — including someone listening to a screen reader — what the field is asking for. Get both right and the browser handles most of the work before you write a single line of JavaScript.

The constraint attributes

Four attributes carry most of the weight, and each one fires under different conditions:

  • required — the control must have a value. This is the only common constraint that an empty field violates. It works on the text-style types, on date, number, checkbox, radio, and file, and on <select> and <textarea>. It does nothing on range and color, which always have a value, on hidden, which the user cannot fill in, or on the button types.
  • type — the input type itself is a constraint. type="email" checks that the value is shaped like an address, type="url" demands an absolute URL, and type="number" restricts the value to a number and makes min, max, and step meaningful.
  • pattern — a regular expression the value must match. The regex is implicitly anchored: the browser behaves as if ^(?: were added at the start and )$ at the end, so it must match the whole value, never a substring. It applies only to the text, search, url, tel, email, and password types.
  • minlength and maxlength — character counts, available on text-style inputs and <textarea>. maxlength stops the user from typing past the limit; minlength stops nothing, it only reports a violation once the user has edited the value.

Labels are not decoration

A form control needs an accessible name, and a <label> is the normal way to give it one. Explicit association uses for on the label pointing at the id of a labelable control — <input> (except hidden), <select>, <textarea>, <button>, <meter>, <output>, <progress> — and never at its name. You can also nest the control inside the label for implicit association. Either way the label becomes a click target that focuses the control; explicit association is the safer default because it survives whatever markup you need to build around the pair.

A placeholder is not a label. It disappears the moment someone types, its low contrast fails low-vision users, and although a browser may fall back to it when nothing better is available, that fallback is a last resort rather than a naming strategy. Use a real label and put example text in a separate hint.

Grouping and ARIA

Individual labels cannot express a question that spans several controls. Wrap radio buttons or related checkboxes in a <fieldset> and caption it with a <legend>: the caption comes from the first <legend> in the fieldset, and the content model expects it before the fieldset's other content. Screen readers commonly announce that caption when the user enters the group, and several announce it alongside each option. A <fieldset> already carries the implicit ARIA role of group, so you do not add role="group" yourself.

That points at the first rule of ARIA: prefer native HTML. Reach for ARIA only where HTML has no equivalent — aria-describedby to attach hint or error text to a field, and aria-invalid="true" to flag a control after validation has actually failed. Neither one changes browser behavior; they only change what assistive technology reports. For more background, see the D276 Web Development Foundations study guide.

Practice: Form Validation Accessibility

  1. A ZIP code field is written as <input type="text" pattern="\d{5}">. The user types 123456 and submits the form. What does the browser do?

    • It blocks submission, because the pattern must match the entire value, as if it were wrapped in ^(?: and )$
    • It allows submission, because \d{5} successfully matches the first five digits as a substring
    • It blocks submission only if you rewrite the pattern as ^\d{5}$ with explicit anchors
    • It allows submission, because pattern constraints are ignored unless required is also present
    Show answer & explanation

    Correct answer: It blocks submission, because the pattern must match the entire value, as if it were wrapped in ^(?: and )$. MDN states that a pattern's regular expression must match the entire value, as if ^(?: were implied at the start and )$ at the end, so the extra sixth digit is a patternMismatch violation and submission is blocked. The tempting wrong answer is the substring one: that is how a plain JavaScript regex test would behave, but pattern is anchored for you, which is also why adding your own ^ and $ changes nothing.

  2. The same field, <input type="text" pattern="\d{5}">, has no required attribute. The user leaves it completely empty and submits. What happens?

    • The form submits, because a pattern mismatch is only evaluated when the value is not the empty string
    • The form is blocked, because an empty string does not match \d{5}
    • The form is blocked, because specifying pattern implicitly makes the field required
    • The form submits, but the empty field still matches the :invalid pseudo-class
    Show answer & explanation

    Correct answer: The form submits, because a pattern mismatch is only evaluated when the value is not the empty string. MDN's pattern reference says a constraint violation is reported only if the value is not the empty string and fails to match, so an empty optional field never has the regex applied to it and the form submits. The trap is reasoning purely from the regex — an empty string genuinely does not match \d{5}, but the browser never runs the test. Since no violation exists, the field matches :valid, not :invalid, and only required could have blocked an empty submission.

  3. A developer writes <label for="phone">Phone</label> followed by <input type="tel" name="phone" id="user-phone">. A screen reader announces the input with no name. What is the correct fix?

    • Change the label to for="user-phone" so it matches the input's id
    • Add a title attribute to the <label> so its text is exposed as the input's accessible name
    • Change nothing — the label's for value already matches the input's name attribute, which is what forms the association
    • Wrap the label and input in a <fieldset> with a <legend> reading "Phone"
    Show answer & explanation

    Correct answer: Change the label to for="user-phone" so it matches the input's id. The for attribute references the id of a labelable element, so for="phone" points at an id that does not exist here and no association is formed; matching the actual id, user-phone, is the fix. Option 3 is the most tempting because both attributes happen to hold the string "phone", but name is only used when submitting form data and never creates a label association. A title on the label describes the label, not the input, and a legend captions a group rather than naming an individual control.

  4. You group three radio buttons under the question "Preferred contact method" inside a <fieldset>. Which statement is correct?

    • The first <legend> in the fieldset supplies the group's caption, and the content model places it before the fieldset's other content
    • The <legend> is purely visual, so the group's accessible name has to come from an aria-label on the <fieldset>
    • Each radio button needs its own <fieldset> and <legend> before its purpose is announced
    • You must add role="group" to the fieldset, because fieldset has no implicit ARIA role
    Show answer & explanation

    Correct answer: The first <legend> in the fieldset supplies the group's caption, and the content model places it before the fieldset's other content. MDN states that the caption for a fieldset is given by the first <legend> element nested inside it, and the element's permitted content is an optional legend followed by flow content — so the legend belongs first. The role="group" option is the most seductive distractor because it sounds like careful accessibility work, but <fieldset> already maps to the group role, making it redundant. Giving each radio its own fieldset would destroy the grouping the legend exists to express.

  5. A developer removes required from <input type="email" required> and replaces it with aria-required="true". What is the practical result?

    • A screen reader still announces the field as required, but the browser no longer blocks submission of an empty field
    • Nothing changes, since aria-required is the accessible equivalent of required
    • The browser still blocks empty submission, but screen readers no longer announce the field as required
    • Both behaviors are lost, because aria-required only applies to elements with a custom ARIA role
    Show answer & explanation

    Correct answer: A screen reader still announces the field as required, but the browser no longer blocks submission of an empty field. MDN is explicit that ARIA only modifies the accessibility tree and does not change an element's function or behavior, so aria-required conveys the required state while enforcing nothing. The "nothing changes" answer is the common misconception — MDN notes that aria-required="true" has no bearing on the optionality of the element, which is why native required is recommended on semantic controls. Option 4 is also false: MDN says aria-required can be used with HTML form elements and is not limited to elements with an assigned ARIA role.

  6. A signup form uses <input type="email" required> and the user enters sam@localhost. What does the browser do on submit?

    • It submits the form, because the built-in email check does not require a dot in the domain
    • It blocks submission, because a valid address must end in a top-level domain such as .com
    • It blocks submission, because the browser confirms the domain resolves before accepting the value
    • It submits only because required is present; without required the value would be rejected
    Show answer & explanation

    Correct answer: It submits the form, because the built-in email check does not require a dot in the domain. The validation regex MDN documents for type="email" requires a local part, an @, and one domain label, but the dotted portion that follows is quantified with * — zero or more — so sam@localhost passes. Browsers never perform DNS lookups or confirm a mailbox exists; MDN notes that passing this check does not mean the address exists, which is why you must still verify server-side. The required attribute is unrelated here: it only governs whether an empty value is allowed.

Putting it together

Here is a small block that uses every idea on this page at once:

<fieldset>
  <legend>Shipping address</legend>

  <label for="zip">ZIP code</label>
  <input type="text" id="zip" name="zip"
         required
         pattern="\d{5}"
         title="Five digits, for example 84119"
         aria-describedby="zip-hint">
  <p id="zip-hint">Five digits, for example 84119.</p>
</fieldset>

The legend captions the group, the label names the control through for/id, required catches an empty field, pattern catches a wrong shape, and aria-describedby attaches the hint so it is announced after the accessible name. Browsers may include the title in the pattern-mismatch message, but MDN warns against relying on it: a tooltip leaves out keyboard-only and touch-only users, so the visible hint is doing the real work.

Mistakes people actually make

  • Putting pattern on type="number". It is silently ignored. pattern applies only to text, search, url, tel, email, and password. For numeric ranges use min, max, and step; for a fixed-length numeric string such as a ZIP or phone number, use type="text" or type="tel" so pattern works.
  • Expecting minlength to behave like maxlength. maxlength physically stops typing at the limit. minlength lets the user type anything and reports a tooShort violation only at validation time, and only once the user has changed the value — an untouched empty optional field submits regardless.
  • Setting aria-invalid="true" in the initial markup. Its default is already false, and no HTML attribute sets it for you. MDN's guidance is to set it with JavaScript as the result of a validation process, not before the user has attempted to submit, and to pair it with a visible message.
  • Nesting a link inside a label. In an "I agree to the <a>Terms</a>" checkbox label, the link competes with the checkbox for activation. Move the link outside the label — and for the same reason, keep headings out of labels and use CSS for the visual weight.

How to reason about the tricky cases

When you are unsure whether a form will submit, ask one question first: is the value empty? If it is, only required can stop the submission. pattern, minlength, and the type checks behind email and url all pass on an empty string by design, because a blank optional field is a legitimate answer. If the value is not empty, every applicable constraint is evaluated and all of them must pass.

The second question is who is this for? Constraint attributes are a convenience for the person filling in the form — anyone can edit your HTML or post directly to your endpoint, so client-side validation is never a security boundary. Validate again on the server, every time.

For the full attribute tables, see MDN on client-side form validation. Then work through more D276 practice questions to lock it in.

Want someone to walk you through this?

Book 1-on-1 prep for WGU D276 — original coaching, never exam content.

Stuck on this topic? WhatsApp us on +1 646 980 4914.

Working through the whole course? Read the full WGU D276 study guide, or see every WGU D276 practice topic.

More WGU D276 practice

Html Document Structure

The five lines at the top of every HTML file are not decoration. Here is what the doctype, the html/head/body split, meta charset, and the viewport tag each do — why the browser misbehaves when you leave one out, and how to reason about the cases that trip people up.

Semantic Structure Tags

Semantic structure tags describe what a block of content is, not how it looks. This lesson explains the difference between article, section, aside, main, nav, header and footer — including the syndication test that settles article vs. section, the strict placement rules for main, and how header and footer change meaning depending on where they sit — then gives you practice questions with worked explanations.

Headings Text Links Lists

Heading elements rank content instead of sizing it, strong and em carry meaning that b and i do not, a fragment link points at an element's id, and ul, ol, and dl each describe a different kind of grouping. Work through how each one behaves, then test yourself on the cases people actually get wrong.

Images And Alt Text

An image starts with one element and one honest description. From there, srcset, sizes, and picture answer a single question: which file should the browser download on this screen? This guide walks through alt text, figure and figcaption, resolution switching, and art direction, then gives you six practice questions with full explanations.

Html5 Audio And Video

The audio and video elements embed media without a plugin. Learn how the browser chooses among source children, which MIME types to use for MP4, WebM, and MP3, what controls and preload actually do, and why fallback content between the tags is not an error message. Includes practice questions with full explanations.

Html Tables

A plain-English walkthrough of HTML table markup for WGU D276: how table, caption, thead, tbody, tr, th and td nest, what the scope attribute actually does for assistive technology, and how colspan and rowspan reshape the grid — plus practice questions with worked explanations.