Core Forms includes built-in accessibility enhancements that run automatically on every form. These ensure forms meet WCAG standards without requiring any extra configuration.
Automatic Enhancements
The cf_enhance_accessibility() function processes form markup at render time (hooked to cf_form_markup at priority 100) and applies these improvements:
ARIA Required Attributes
All fields with the required HTML attribute automatically receive aria-required="true". This ensures screen readers announce the field as required.
Input ID Generation
Form inputs that lack an id attribute get one generated automatically. The ID is derived from the field’s name attribute. Duplicate IDs are avoided by appending a counter. This is essential for label association.
Label Association
Labels without a for attribute are automatically associated with their inputs:
- If a label wraps an input element, the
forattribute is set to the input’s ID. - If a label is adjacent to an input (in the same parent container), the
forattribute is set to the nearest input’s ID.
Autocomplete Attributes
Common field types receive appropriate autocomplete attributes based on their name or type:
- Fields named “email” get
autocomplete="email" - Fields named “name” get
autocomplete="name" - Fields named “first_name” get
autocomplete="given-name" - Fields named “last_name” get
autocomplete="family-name" - Fields named “phone” or “tel” get
autocomplete="tel" - Fields named “address” get
autocomplete="street-address" - Fields named “city” get
autocomplete="address-level2" - Fields named “state” get
autocomplete="address-level1" - Fields named “zip” or “postal” get
autocomplete="postal-code" - Fields named “country” get
autocomplete="country-name" - Fields named “url” or “website” get
autocomplete="url"
Fields with type="email", type="tel", or type="url" also receive the matching autocomplete value.
Input Type Correction
Text inputs with names containing “email”, “phone”, “tel”, “url”, or “website” are automatically upgraded to the appropriate input type. For example, <input type="text" name="email"> becomes <input type="email" name="email">. The corresponding inputmode attribute is also set for better mobile keyboard support.
Fieldset Legends
Fieldsets without a <legend> element get one added automatically. The legend text is “Field Group” with a screen-reader-text class, making it invisible but available to screen readers.
JavaScript Accessibility (accessibility.js)
A dedicated accessibility script provides runtime enhancements:
Message Announcements
The .cf-messages container uses role="status" and aria-live="polite" so screen readers announce success and error messages when they appear. Focus is moved to the message container after submission.
Field Validation State
When a field fails validation, aria-invalid="true" is set. When the user corrects the value, the attribute is removed.
Submit Button State
During form submission, the submit button receives aria-busy="true" and is disabled to prevent double submission. After the response is received, these are reset.
Conditional Field Tab Order
Fields hidden by conditional logic (via data-show-if or data-hide-if) are removed from the tab order by setting tabindex="-1". When the fields become visible again, the original tab order is restored. This prevents keyboard users from tabbing into hidden fields.
Skip Links
For forms with 10 or more fields, a skip link is added that lets keyboard users jump directly to the submit button. This follows the same pattern as WordPress’s skip-to-content link.
Form Element Attributes
The <form> element includes:
novalidate– Disables browser-native validation in favor of the plugin’s AJAX validation.aria-label– Set to the form title, providing a label for the form landmark.
Noscript Fallback
Every form includes a <noscript> tag with a message asking users to enable JavaScript. This has role="alert" for screen readers.
Best Practices for Form Authors
While Core Forms handles most accessibility concerns automatically, you can improve the experience by:
- Writing descriptive labels. Every input should have a visible
<label>element. - Using
<fieldset>and<legend>for groups. Radio button groups and checkbox groups should be wrapped in a fieldset with a descriptive legend. - Providing placeholder text as hints, not labels. Placeholders disappear when typing and should not be the only label for a field.
- Using meaningful error messages. Customize messages in the Messages tab to be specific about what went wrong and how to fix it.