Loading Developer Playground

Loading ...

Skip to main content
ARIA ATTRIBUTEWidget Attributes

aria-required

Indicates that user input is required on the element before a form may be submitted. Essential for accessible form validation and helping screen reader users understand mandatory fields.

Value Type
true | false
Common Use
Form Validation
Compare To
HTML required

Overview

The aria-required attribute indicates that user input is required on the element before a form may be submitted. Screen readers announce "required" when users focus on these fields.

Unlike the HTML required attribute, aria-required does NOT trigger browser validation. It only communicates the requirement to assistive technologies. For native form elements, use both attributes together.

When to Use aria-required

Use aria-required for custom widgets (comboboxes, custom selects, etc.) where the HTML required attribute isn't applicable. For native inputs, use required (which automatically sets aria-required).

Live Demo: Required Form Fields

indicates required fields

Screen reader announcement: When focusing on the Name field: "Full Name, required, edit text". For Phone: "Phone Number, edit text" (no "required" announcement).

Attribute Values

true

User input is required on this element before form submission. Screen readers announce "required" when the user focuses on this field.

Screen reader: "[Label], required, edit text"
false(default)

The element is optional. This is the default when the attribute is not present. No "required" announcement is made.

Screen reader: "[Label], edit text"

required vs aria-required

required(HTML attribute)

  • • Triggers browser validation
  • • Shows native error messages
  • • Prevents form submission if empty
  • • Automatically sets aria-required
  • • Only works on form elements

Use when: You want browser-native validation on standard form elements.

aria-required="true"(ARIA attribute)

  • • Only announces to screen readers
  • • NO browser validation
  • • Allows form submission
  • • Must validate in JavaScript
  • • Works on any element

Use when: Building custom widgets or need custom validation.

Code Examples

Basic Usage

<!-- Basic aria-required usage -->
<form>
  <label for="name">
    Full Name <span aria-hidden="true">*</span>
  </label>
  <input 
    type="text" 
    id="name"
    aria-required="true"
  />
  
  <label for="email">
    Email <span aria-hidden="true">*</span>
  </label>
  <input 
    type="email" 
    id="email"
    aria-required="true"
  />
  
  <label for="phone">Phone (optional)</label>
  <input 
    type="tel" 
    id="phone"
    aria-required="false"
  />
  
  <button type="submit">Submit</button>
</form>

<!-- Screen reader announces: "Full Name, required, edit text" -->

required vs aria-required

<!-- aria-required vs HTML required attribute -->

<!-- HTML required attribute -->
<input type="text" required />
<!-- 
  • Browser enforces validation
  • Shows built-in error messages
  • Prevents form submission
  • Announces "required" to screen readers
-->

<!-- aria-required attribute -->
<input type="text" aria-required="true" />
<!--
  • ONLY announces "required" to screen readers
  • NO browser validation
  • Allows form submission
  • Must implement validation in JavaScript
-->

<!-- Best Practice: Use BOTH together -->
<input 
  type="text" 
  required
  aria-required="true"
/>
<!-- Provides both browser validation AND clear AT support -->

Custom Widgets

<!-- Custom widgets need aria-required -->

<!-- Custom combobox -->
<div 
  role="combobox" 
  aria-required="true"
  aria-expanded="false"
  aria-haspopup="listbox"
  aria-labelledby="country-label"
  tabindex="0"
>
  <span id="country-label">Country</span>
  <span>Select a country</span>
</div>

<!-- Custom listbox -->
<div 
  role="listbox"
  aria-required="true"
  aria-labelledby="role-label"
  tabindex="0"
>
  <span id="role-label">Role</span>
  <div role="option">Admin</div>
  <div role="option">User</div>
  <div role="option">Guest</div>
</div>

<!-- Custom radio group -->
<div 
  role="radiogroup"
  aria-required="true"
  aria-labelledby="size-label"
>
  <span id="size-label">Size (required)</span>
  <div role="radio" aria-checked="false">Small</div>
  <div role="radio" aria-checked="false">Medium</div>
  <div role="radio" aria-checked="false">Large</div>
</div>

Visual Indicators

<!-- Visual indicators for required fields -->

<!-- Using asterisk (hide from screen readers) -->
<label for="email">
  Email Address
  <span aria-hidden="true" class="required-indicator">*</span>
</label>
<input 
  type="email" 
  id="email" 
  required
  aria-required="true"
/>

<!-- Using text (visible to all) -->
<label for="name">
  Full Name <span class="required-text">(required)</span>
</label>
<input 
  type="text" 
  id="name" 
  required
  aria-required="true"
/>

<!-- Form-level instruction -->
<p class="form-instructions">
  Fields marked with <span aria-hidden="true">*</span> 
  <span class="sr-only">an asterisk</span> are required.
</p>

<style>
  .required-indicator {
    color: #dc2626;
    margin-left: 0.25rem;
  }
  .required-text {
    color: #6b7280;
    font-size: 0.875rem;
  }
  .sr-only {
    position: absolute;
    width: 1px;
    height: 1px;
    overflow: hidden;
    clip: rect(0, 0, 0, 0);
  }
</style>

React Component

// React Form with Required Fields
import { useState } from 'react';

function RequiredInput({ 
  label, 
  type = 'text', 
  required = false,
  error,
  ...props 
}) {
  const inputId = props.id || props.name;
  const errorId = `${inputId}-error`;
  
  return (
    <div className="form-field">
      <label htmlFor={inputId}>
        {label}
        {required && (
          <span aria-hidden="true" className="required-star">*</span>
        )}
      </label>
      <input
        {...props}
        type={type}
        id={inputId}
        required={required}
        aria-required={required}
        aria-invalid={!!error}
        aria-describedby={error ? errorId : undefined}
        className={error ? 'input-error' : ''}
      />
      {error && (
        <span id={errorId} className="error-message" role="alert">
          {error}
        </span>
      )}
    </div>
  );
}

// Form Component
function ContactForm() {
  const [errors, setErrors] = useState({});
  const [formData, setFormData] = useState({
    name: '',
    email: '',
    message: ''
  });

  const validate = () => {
    const newErrors = {};
    if (!formData.name.trim()) {
      newErrors.name = 'Name is required';
    }
    if (!formData.email.trim()) {
      newErrors.email = 'Email is required';
    } else if (!/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(formData.email)) {
      newErrors.email = 'Invalid email format';
    }
    if (!formData.message.trim()) {
      newErrors.message = 'Message is required';
    }
    setErrors(newErrors);
    return Object.keys(newErrors).length === 0;
  };

  const handleSubmit = (e) => {
    e.preventDefault();
    if (validate()) {
      // Submit form
      console.log('Form submitted:', formData);
    }
  };

  return (
    <form onSubmit={handleSubmit} noValidate>
      <p className="form-note">
        <span aria-hidden="true">*</span> Required fields
      </p>
      
      <RequiredInput
        name="name"
        label="Full Name"
        required
        value={formData.name}
        onChange={(e) => setFormData({...formData, name: e.target.value})}
        error={errors.name}
      />
      
      <RequiredInput
        name="email"
        type="email"
        label="Email Address"
        required
        value={formData.email}
        onChange={(e) => setFormData({...formData, email: e.target.value})}
        error={errors.email}
      />
      
      <RequiredInput
        name="message"
        label="Message"
        required
        value={formData.message}
        onChange={(e) => setFormData({...formData, message: e.target.value})}
        error={errors.message}
      />
      
      <button type="submit">Send Message</button>
    </form>
  );
}

Best Practices

Use both required and aria-required on native form elements for maximum compatibility

Provide visual indication of required fields (asterisk, "required" text, etc.)

Include a form-level instruction explaining required field indicators

Use aria-required on custom widgets where HTML required doesn't apply

Implement proper validation and error messaging for required fields

Hide decorative asterisks from screen readers with aria-hidden="true"

×

Don't rely only on aria-required for validation—implement JavaScript checks

×

Don't use color alone to indicate required fields—add text or symbols

×

Don't forget to provide error messages when required fields are empty

×

Don't make too many fields required—consider what's truly necessary

Common Use Cases

Contact form name/email fields
Registration form mandatory fields
Checkout billing information
Custom combobox selections
Custom radio group choices
Survey mandatory questions
Login username/password fields
Payment card details

Related Attributes

Specifications & Resources