pages.accessibleForms.labelsAndAssociations.title

components.exampleToggle.badExample

pages.accessibleForms.labelsAndAssociations.bad.heading

pages.accessibleForms.labelsAndAssociations.bad.remember
<!-- pages.accessibleForms.codeExamples.labelsAndAssociations.badComment -->
<form>
  <h4>pages.accessibleForms.labelsAndAssociations.bad.heading</h4>

  <!-- pages.accessibleForms.codeExamples.labelsAndAssociations.noLabel -->
  <input
    type="email"
    placeholder="pages.accessibleForms.labelsAndAssociations.bad.email">

  <!-- pages.accessibleForms.codeExamples.labelsAndAssociations.noLabelNoAutocomplete -->
  <input
    type="password"
    placeholder="pages.accessibleForms.labelsAndAssociations.bad.password">

  <!-- pages.accessibleForms.codeExamples.labelsAndAssociations.checkboxNotAssociated -->
  <input type="checkbox">
  <span>pages.accessibleForms.labelsAndAssociations.bad.remember</span>

  <button type="submit">pages.accessibleForms.labelsAndAssociations.bad.submit</button>
</form>

components.exampleToggle.goodExample

pages.accessibleForms.labelsAndAssociations.good.heading

pages.accessibleForms.labelsAndAssociations.good.emailHelp
pages.accessibleForms.labelsAndAssociations.good.passwordHelp
<!-- pages.accessibleForms.codeExamples.labelsAndAssociations.goodComment -->
<form>
  <h4>pages.accessibleForms.labelsAndAssociations.good.heading</h4>

  <!-- pages.accessibleForms.codeExamples.labelsAndAssociations.labelWithFor -->
  <label for="email-good">pages.accessibleForms.labelsAndAssociations.good.emailLabel</label>
  <input
    type="email"
    id="email-good"
    placeholder="pages.accessibleForms.labelsAndAssociations.good.emailPlaceholder"
    required
    aria-describedby="email-help"
    autocomplete="email">
  <div id="email-help">
    pages.accessibleForms.labelsAndAssociations.good.emailHelp
  </div>

  <!-- pages.accessibleForms.codeExamples.labelsAndAssociations.labelWithInstructions -->
  <label for="password-good">pages.accessibleForms.labelsAndAssociations.good.passwordLabel</label>
  <input
    type="password"
    id="password-good"
    required
    aria-describedby="password-help"
    autocomplete="current-password">
  <div id="password-help">
    pages.accessibleForms.labelsAndAssociations.good.passwordHelp
  </div>

  <!-- pages.accessibleForms.codeExamples.labelsAndAssociations.checkboxCorrectlyAssociated -->
  <input type="checkbox" id="remember-good">
  <label for="remember-good">pages.accessibleForms.labelsAndAssociations.good.remember</label>

  <button type="submit">pages.accessibleForms.labelsAndAssociations.good.submit</button>
</form>

components.exampleToggle.explanation pages.accessibleForms.labelsAndAssociations.explanation

pages.accessibleForms.validation.title

components.exampleToggle.badExample

pages.accessibleForms.validation.bad.heading

<!-- pages.accessibleForms.codeExamples.validation.badComment -->
<form @submit.prevent="submitBadForm">
  <h4>pages.accessibleForms.validation.bad.heading</h4>

  <!-- pages.accessibleForms.codeExamples.validation.noAssociation -->
  <label>pages.accessibleForms.validation.bad.name</label>
  <input
    type="text"
    v-model="badForm.name"
    :class="{ 'error': submitted && !badForm.name }">

  <!-- pages.accessibleForms.codeExamples.validation.visualErrorOnly -->
  <label>pages.accessibleForms.validation.bad.email</label>
  <input
    type="email"
    v-model="badForm.email"
    :class="{ 'error': submitted && !isValidEmail(badForm.email) }">

  <!-- pages.accessibleForms.codeExamples.validation.noErrorInfo -->
  <label>pages.accessibleForms.validation.bad.age</label>
  <input
    type="number"
    v-model="badForm.age"
    :class="{ 'error': submitted && badForm.age < 16 }">

  <!-- pages.accessibleForms.codeExamples.validation.genericMessage -->
  <div v-if="submitted && badFormErrors.length">
    ❌ pages.accessibleForms.validation.bad.errorSummary
  </div>

  <button type="submit">pages.accessibleForms.validation.bad.submit</button>
</form>

components.exampleToggle.goodExample

pages.accessibleForms.validation.good.heading

pages.accessibleForms.validation.good.ageHelp
<!-- pages.accessibleForms.codeExamples.validation.goodComment -->
<form @submit.prevent="submitGoodForm" novalidate>
  <h4>pages.accessibleForms.validation.good.heading</h4>

  <!-- pages.accessibleForms.codeExamples.validation.errorSummary -->
  <div
    v-if="submitted && goodFormErrors.length"
    role="alert"
    aria-labelledby="error-summary-title">
    <h5 id="error-summary-title">pages.accessibleForms.validation.good.errorSummaryTitle</h5>
    <ul>
      <li v-for="error in goodFormErrors" :key="error.field">
        <a :href="`#${error.field}-good-form`">
          
        </a>
      </li>
    </ul>
  </div>

  <!-- pages.accessibleForms.codeExamples.validation.specificErrorAssociated -->
  <label for="name-good-form">pages.accessibleForms.validation.good.nameLabel *</label>
  <input
    type="text"
    id="name-good-form"
    v-model="goodForm.name"
    required
    aria-invalid="submitted && !goodForm.name"
    aria-describedby="name-error">
  <div
    v-if="submitted && !goodForm.name"
    id="name-error"
    role="alert">
    ❌ pages.accessibleForms.validation.good.nameError
  </div>

  <button type="submit">pages.accessibleForms.validation.good.submit</button>
</form>

components.exampleToggle.explanation pages.accessibleForms.validation.explanation

pages.accessibleForms.fieldsets.title

components.exampleToggle.badExample

pages.accessibleForms.fieldsets.bad.heading

<!-- pages.accessibleForms.codeExamples.fieldsets.badComment -->
<form>
  <h4>pages.accessibleForms.fieldsets.bad.heading</h4>

  <!-- pages.accessibleForms.codeExamples.fieldsets.mixedElements -->
  <div>
    <input type="radio" name="contact-bad"
           id="email-contact-bad" value="email">
    <label for="email-contact-bad">pages.accessibleForms.fieldsets.bad.email</label>

    <input type="checkbox" id="newsletter-bad"
           value="newsletter">
    <label for="newsletter-bad">pages.accessibleForms.fieldsets.bad.newsletter</label>
  </div>

  <div>
    <input type="radio" name="contact-bad"
           id="phone-contact-bad" value="phone">
    <label for="phone-contact-bad">pages.accessibleForms.fieldsets.bad.phone</label>

    <!-- pages.accessibleForms.codeExamples.fieldsets.textFieldNoContext -->
    <input type="text" placeholder="pages.accessibleForms.fieldsets.bad.name">
  </div>

  <div>
    <input type="checkbox" id="offers-bad" value="offers">
    <label for="offers-bad">pages.accessibleForms.fieldsets.bad.offers</label>

    <input type="radio" name="contact-bad"
           id="sms-contact-bad" value="sms">
    <label for="sms-contact-bad">pages.accessibleForms.fieldsets.bad.sms</label>
  </div>

  <!-- pages.accessibleForms.codeExamples.fieldsets.selectNoContext -->
  <select>
    <option>pages.accessibleForms.fieldsets.bad.frequency</option>
    <option>pages.accessibleForms.fieldsets.bad.daily</option>
    <option>pages.accessibleForms.fieldsets.bad.weekly</option>
  </select>

  <button type="submit">pages.accessibleForms.fieldsets.bad.submit</button>
</form>

components.exampleToggle.goodExample

pages.accessibleForms.fieldsets.good.heading

pages.accessibleForms.fieldsets.good.personalInfo.title
pages.accessibleForms.fieldsets.good.personalInfo.nameDescription
pages.accessibleForms.fieldsets.good.personalInfo.emailDescription
pages.accessibleForms.fieldsets.good.contactMethod.title *
pages.accessibleForms.fieldsets.good.commTypes.title

pages.accessibleForms.fieldsets.good.commTypes.description

pages.accessibleForms.fieldsets.good.frequency.title
pages.accessibleForms.fieldsets.good.frequency.description
<!-- pages.accessibleForms.codeExamples.fieldsets.goodComment -->
<form>
  <h4>pages.accessibleForms.fieldsets.good.heading</h4>

  <!-- pages.accessibleForms.codeExamples.fieldsets.personalInfoSection -->
  <div role="group" aria-labelledby="personal-info-title">
    <h5 id="personal-info-title">
      pages.accessibleForms.fieldsets.good.personalInfo.title
    </h5>

    <label for="name-good">pages.accessibleForms.fieldsets.good.personalInfo.nameLabel *</label>
    <input
      type="text"
      id="name-good"
      name="name"
      required
      aria-required="true"
      aria-describedby="name-desc">
    <span id="name-desc">
      pages.accessibleForms.fieldsets.good.personalInfo.nameDescription
    </span>
  </div>

  <!-- pages.accessibleForms.codeExamples.fieldsets.radioGroup -->
  <div
    role="radiogroup"
    aria-labelledby="contact-method-title"
    aria-required="true">
    <h5 id="contact-method-title">
      pages.accessibleForms.fieldsets.good.contactMethod.title *
    </h5>

    <input
      type="radio"
      name="contact-good"
      id="email-contact-good"
      value="email"
      required>
    <label for="email-contact-good">pages.accessibleForms.fieldsets.good.contactMethod.email</label>

    <input
      type="radio"
      name="contact-good"
      id="phone-contact-good"
      value="phone"
      required>
    <label for="phone-contact-good">pages.accessibleForms.fieldsets.good.contactMethod.phone</label>
  </div>

  <!-- pages.accessibleForms.codeExamples.fieldsets.checkboxGroup -->
  <div role="group" aria-labelledby="comm-types-title">
    <h5 id="comm-types-title">pages.accessibleForms.fieldsets.good.commTypes.title</h5>
    <p id="comm-types-desc">
      pages.accessibleForms.fieldsets.good.commTypes.description
    </p>

    <input
      type="checkbox"
      id="newsletter-good"
      value="newsletter"
      aria-describedby="comm-types-desc">
    <label for="newsletter-good">pages.accessibleForms.fieldsets.good.commTypes.newsletter</label>
  </div>

  <button type="submit">
    pages.accessibleForms.fieldsets.good.submit
  </button>
</form>

components.exampleToggle.explanation pages.accessibleForms.fieldsets.explanation

pages.accessibleForms.complexValidation.title

components.exampleToggle.badExample

pages.accessibleForms.complexValidation.bad.heading

<!-- pages.accessibleForms.codeExamples.complexValidation.badComment -->
<form>
  <h4>pages.accessibleForms.complexValidation.bad.heading</h4>

  <!-- pages.accessibleForms.codeExamples.complexValidation.immediateValidation -->
  <label>pages.accessibleForms.complexValidation.bad.username</label>
  <input
    type="text"
    v-model="complexBadForm.username"
    @input="validateUsernameBad"
    :class="{ 'error': usernameBadError }">
  <!-- pages.accessibleForms.codeExamples.complexValidation.constantErrorToggle -->
  <div v-if="usernameBadError">
    
  </div>

  <!-- pages.accessibleForms.codeExamples.complexValidation.noAriaDescribedby -->
  <label>pages.accessibleForms.complexValidation.bad.email</label>
  <input
    type="email"
    v-model="complexBadForm.email"
    @input="validateEmailBad"
    :class="{ 'error': emailBadError }">
  <div v-if="emailBadError"></div>

  <!-- pages.accessibleForms.codeExamples.complexValidation.shortMessages -->
  <!-- pages.accessibleForms.codeExamples.complexValidation.noAutocomplete -->
  <label>pages.accessibleForms.complexValidation.bad.password</label>
  <input
    type="password"
    v-model="complexBadForm.password"
    @input="validatePasswordBad"
    :class="{ 'error': passwordBadError }">
  <div v-if="passwordBadError"></div>

  <button type="submit">pages.accessibleForms.complexValidation.bad.submit</button>
</form>

components.exampleToggle.goodExample

pages.accessibleForms.complexValidation.good.heading

pages.accessibleForms.complexValidation.good.usernameRequirements.title
  • pages.accessibleForms.complexValidation.good.usernameRequirements.minLength
  • pages.accessibleForms.complexValidation.good.usernameRequirements.validChars
pages.accessibleForms.complexValidation.good.passwordStrength.title
pages.accessibleForms.complexValidation.good.passwordStrength.length
pages.accessibleForms.complexValidation.good.passwordStrength.uppercase
pages.accessibleForms.complexValidation.good.passwordStrength.number
pages.accessibleForms.complexValidation.good.passwordStrength.special
<!-- pages.accessibleForms.codeExamples.complexValidation.goodComment -->
<form>
  <h4>pages.accessibleForms.complexValidation.good.heading</h4>

  <!-- pages.accessibleForms.codeExamples.complexValidation.validationOnBlur -->
  <label for="username-complex">pages.accessibleForms.complexValidation.good.usernameLabel *</label>
  <input
    type="text"
    id="username-complex"
    v-model="complexGoodForm.username"
    @blur="validateUsernameGood"
    :class="{ error: usernameGoodError,
              success: usernameGoodValid }"
    aria-describedby="username-requirements username-feedback"
    aria-invalid="!!usernameGoodError"
    required>

  <!-- pages.accessibleForms.codeExamples.complexValidation.clearInstructions -->
  <div id="username-requirements">
    <h6>pages.accessibleForms.complexValidation.good.usernameRequirements.title</h6>
    <ul>
      <li :class="{ valid: complexGoodForm.username.length >= 3 }">
        pages.accessibleForms.complexValidation.good.usernameRequirements.minLength
      </li>
      <li :class="{ valid: /^[a-zA-Z0-9_]+$/.test(username) }">
        pages.accessibleForms.complexValidation.good.usernameRequirements.validChars
      </li>
    </ul>
  </div>

  <!-- pages.accessibleForms.codeExamples.complexValidation.accessibleFeedback -->
  <div
    v-if="usernameGoodError"
    id="username-feedback"
    role="alert"
    aria-live="polite">
    ❌ 
  </div>
  <div
    v-else-if="usernameGoodValid"
    id="username-feedback"
    role="status"
    aria-live="polite">
    ✅ pages.accessibleForms.complexValidation.good.usernameValid
  </div>

  <!-- pages.accessibleForms.codeExamples.complexValidation.passwordStrengthIndicator -->
  <label for="password-complex">pages.accessibleForms.complexValidation.good.passwordLabel *</label>
  <input
    type="password"
    id="password-complex"
    v-model="complexGoodForm.password"
    @input="validatePasswordGood"
    aria-describedby="password-strength"
    autocomplete="new-password"
    required>

  <div id="password-strength">
    <h6>pages.accessibleForms.complexValidation.good.passwordStrength.title</h6>
    <div class="strength-indicator">
      <div
        class="strength-bar"
        :class="`strength-${passwordStrength}`"
        :style="{ width: `${passwordStrength * 25}%` }">
      </div>
    </div>
  </div>

  <button type="submit" :disabled="!isFormValid">
    pages.accessibleForms.complexValidation.good.submit
  </button>
</form>

components.exampleToggle.explanation pages.accessibleForms.complexValidation.explanation