মূল কনটেন্টে যান
🐹
emberjs learning
গাইড•4 · Accessibility Best Practices

Form Labels and Error Announcements

impact · HIGHEssential for screen reader usersplan · দিন ০৬১
আগে নিজে — এই কোডে কী ভুল, ঠিকটা কেমন হবে?

Incorrect (missing labels and announcements):

// app/components/form.gjs
<template>
  <form {{on "submit" this.handleSubmit}}>
    <input type="email" value={{this.email}} {{on "input" this.updateEmail}} placeholder="Email" />

    {{#if this.emailError}}
      <span>{{this.emailError}}</span>
    {{/if}}

    <button type="submit">Submit</button>
  </form>
</template>
পুরো rule · Correct আর ব্যাখ্যা — আগে নিজে লিখুন, তারপর খুলুন

All form inputs must have associated labels, and validation errors should be announced to screen readers using ARIA live regions.

Incorrect (missing labels and announcements):

// app/components/form.gjs
<template>
  <form {{on "submit" this.handleSubmit}}>
    <input type="email" value={{this.email}} {{on "input" this.updateEmail}} placeholder="Email" />

    {{#if this.emailError}}
      <span>{{this.emailError}}</span>
    {{/if}}

    <button type="submit">Submit</button>
  </form>
</template>

Correct (with labels and announcements):

// app/components/form.gjs
<template>
  <form {{on "submit" this.handleSubmit}}>
    <div>
      <label for="email-input">
        Email Address
        <span aria-hidden="true">*</span>
      </label>

      <input
        id="email-input"
        type="email"
        value={{this.email}}
        {{on "input" this.updateEmail}}
        aria-describedby={{if this.emailError "email-error"}}
        aria-invalid={{if this.emailError "true"}}
        required={{this.isEmailRequired}}
      />

      {{#if this.emailError}}
        <span id="email-error" role="alert" aria-live="polite">
          {{this.emailError}}
        </span>
      {{/if}}
    </div>

    <button type="submit" disabled={{this.isSubmitting}}>
      {{#if this.isSubmitting}}
        <span aria-live="polite">Submitting...</span>
      {{else}}
        Submit
      {{/if}}
    </button>
  </form>
</template>

For complex forms, use platform-native validation with custom logic:

// app/components/user-form.gjs
import Component from '@glimmer/component';
import { tracked } from '@glimmer/tracking';
import { on } from '@ember/modifier';

class UserForm extends Component {
  @tracked errorMessages = {};

  validateEmail = (event) => {
    // Custom business logic validation
    const input = event.target;
    const value = input.value;

    if (!value) {
      input.setCustomValidity('Email is required');
      return false;
    }

    if (!input.validity.valid) {
      input.setCustomValidity('Must be a valid email');
      return false;
    }

    // Additional custom validation (e.g., check if email is already taken)
    if (value === 'taken@example.com') {
      input.setCustomValidity('This email is already registered');
      return false;
    }

    input.setCustomValidity('');
    return true;
  };

  handleSubmit = async (event) => {
    event.preventDefault();
    const form = event.target;

    // Run custom validations
    const emailInput = form.querySelector('[name="email"]');
    const fakeEvent = { target: emailInput };
    this.validateEmail(fakeEvent);

    // Use native validation check
    if (!form.checkValidity()) {
      form.reportValidity();
      return;
    }

    const formData = new FormData(form);
    await this.args.onSubmit(formData);
  };

  <template>
    <form {{on "submit" this.handleSubmit}}>
      <label for="user-email">
        Email
        <input
          id="user-email"
          type="email"
          name="email"
          required
          value={{@user.email}}
          {{on "blur" this.validateEmail}}
        />
      </label>
      <button type="submit">Save</button>
    </form>
  </template>
}

Always associate labels with inputs and announce dynamic changes to screen readers using aria-live regions.

Reference: Ember Accessibility - Application Considerations