Starting with Chrome 149, every native <form> element is exposed with a
form landmark role even when it has no accessible name. Screen readers (NVDA in
browse mode, VoiceOver) announce a form region on entering and leaving every such
form, which is significant browse-mode navigation noise.
Per HTML-AAM, a
<form> maps to the form landmark role only when it has an
accessible name from aria-label, aria-labelledby, or
title. Without a name it must be a generic container, not a landmark.
The two forms below are the repro. Navigate them with a screen reader, or inspect them in chrome://accessibility.
1. Load this page (or the minimal markup below).
2. Open chrome://accessibility/, enable "Internal", select this tab, click "show accessibility tree".
3. Inspect the first <form> (no accessible name).
<!-- Case 1: no accessible name. Per HTML-AAM must NOT be a landmark. -->
<form action="#">
<label>Search <input type="search" name="q"></label>
<button type="submit">Go</button>
</form>
<!-- Case 2: accessible name present. SHOULD be a form landmark. -->
<form action="#" aria-label="Newsletter signup">
<label>Email <input type="email" name="email"></label>
<button type="submit">Subscribe</button>
</form>
| Platform / API | Case 1 (unnamed) — expected | Case 1 — actual (149+) |
|---|---|---|
| Windows IA2 (NVDA) | IA2_ROLE_SECTION | IA2_ROLE_FORM (announced as form) |
| Windows UIA | no landmark | UIA_FormLandmarkTypeId |
| macOS (VoiceOver) | AXGroup (group) | AXSubrole=AXLandmarkForm |
| Linux ATK | ATK_ROLE_FORM (not landmark) | ATK_ROLE_FORM (already correct) |
Case 2 (named) is exposed as a form landmark on all platforms, which is correct.
Regressed by
CL 7257274
(bug 468317749), which made Blink always return Role::kForm for
<form> and pushed the named/unnamed decision to each platform.
The platform mappings used the wrong signal. Because IsLandmark(kForm) is
true, Blink serializes xml-roles="form" (the kRole attribute) on
every kForm node, so a kName || kRole check can never
demote an unnamed native form.
Windows IA2 (used by NVDA) was never updated, Windows UIA keyed off kRole,
and the macOS fix was applied to the Views class instead of the web-content class. Only
Linux/ATK (name-only) was correct.
Use the accessible name as the sole signal on every platform, matching the
shipping Linux behavior: an unnamed <form> becomes a plain
section/group, a named one stays a form landmark.
// ax_platform_node_win.cc (ComputeIA2Role)
case ax::mojom::Role::kForm:
ia2_role = HasStringAttribute(ax::mojom::StringAttribute::kName)
? IA2_ROLE_FORM
: IA2_ROLE_SECTION;
break;
Issue: #525393430 (regression) · #40852121 (original)
Regressing CL: crrev.com/c/7257274
Spec: HTML-AAM <form> · Core-AAM