Skip to content
This repository was archived by the owner on Feb 25, 2025. It is now read-only.

Commit d302cc9

Browse files
authored
Revert "[web:a11y] make header a proper <header> (#55747)" (#55993)
This reverts commit 2fbb0c1. This broke a customer: #55747 (comment)
1 parent 4e6405e commit d302cc9

File tree

6 files changed

+20
-77
lines changed

6 files changed

+20
-77
lines changed

ci/licenses_golden/licenses_flutter

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -43886,7 +43886,6 @@ ORIGIN: ../../../flutter/lib/web_ui/lib/src/engine/semantics.dart + ../../../flu
4388643886
ORIGIN: ../../../flutter/lib/web_ui/lib/src/engine/semantics/accessibility.dart + ../../../flutter/LICENSE
4388743887
ORIGIN: ../../../flutter/lib/web_ui/lib/src/engine/semantics/checkable.dart + ../../../flutter/LICENSE
4388843888
ORIGIN: ../../../flutter/lib/web_ui/lib/src/engine/semantics/focusable.dart + ../../../flutter/LICENSE
43889-
ORIGIN: ../../../flutter/lib/web_ui/lib/src/engine/semantics/header.dart + ../../../flutter/LICENSE
4389043889
ORIGIN: ../../../flutter/lib/web_ui/lib/src/engine/semantics/heading.dart + ../../../flutter/LICENSE
4389143890
ORIGIN: ../../../flutter/lib/web_ui/lib/src/engine/semantics/image.dart + ../../../flutter/LICENSE
4389243891
ORIGIN: ../../../flutter/lib/web_ui/lib/src/engine/semantics/incrementable.dart + ../../../flutter/LICENSE
@@ -46765,7 +46764,6 @@ FILE: ../../../flutter/lib/web_ui/lib/src/engine/semantics.dart
4676546764
FILE: ../../../flutter/lib/web_ui/lib/src/engine/semantics/accessibility.dart
4676646765
FILE: ../../../flutter/lib/web_ui/lib/src/engine/semantics/checkable.dart
4676746766
FILE: ../../../flutter/lib/web_ui/lib/src/engine/semantics/focusable.dart
46768-
FILE: ../../../flutter/lib/web_ui/lib/src/engine/semantics/header.dart
4676946767
FILE: ../../../flutter/lib/web_ui/lib/src/engine/semantics/heading.dart
4677046768
FILE: ../../../flutter/lib/web_ui/lib/src/engine/semantics/image.dart
4677146769
FILE: ../../../flutter/lib/web_ui/lib/src/engine/semantics/incrementable.dart

lib/web_ui/lib/src/engine.dart

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -147,7 +147,6 @@ export 'engine/scene_view.dart';
147147
export 'engine/semantics/accessibility.dart';
148148
export 'engine/semantics/checkable.dart';
149149
export 'engine/semantics/focusable.dart';
150-
export 'engine/semantics/header.dart';
151150
export 'engine/semantics/heading.dart';
152151
export 'engine/semantics/image.dart';
153152
export 'engine/semantics/incrementable.dart';

lib/web_ui/lib/src/engine/semantics.dart

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@
55
export 'semantics/accessibility.dart';
66
export 'semantics/checkable.dart';
77
export 'semantics/focusable.dart';
8-
export 'semantics/header.dart';
98
export 'semantics/heading.dart';
109
export 'semantics/image.dart';
1110
export 'semantics/incrementable.dart';

lib/web_ui/lib/src/engine/semantics/header.dart

Lines changed: 0 additions & 44 deletions
This file was deleted.

lib/web_ui/lib/src/engine/semantics/semantics.dart

Lines changed: 10 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,6 @@ import '../window.dart';
2121
import 'accessibility.dart';
2222
import 'checkable.dart';
2323
import 'focusable.dart';
24-
import 'header.dart';
2524
import 'heading.dart';
2625
import 'image.dart';
2726
import 'incrementable.dart';
@@ -397,17 +396,14 @@ enum SemanticRoleKind {
397396
/// The node's role is to host a platform view.
398397
platformView,
399398

400-
/// Contains a link.
401-
link,
402-
403-
/// Denotes a header.
404-
header,
405-
406399
/// A role used when a more specific role cannot be assigend to
407400
/// a [SemanticsObject].
408401
///
409402
/// Provides a label or a value.
410403
generic,
404+
405+
/// Contains a link.
406+
link,
411407
}
412408

413409
/// Responsible for setting the `role` ARIA attribute, for attaching
@@ -692,18 +688,23 @@ final class GenericRole extends SemanticRole {
692688
return;
693689
}
694690

695-
// Assign one of two roles to the element: group or text.
691+
// Assign one of three roles to the element: group, heading, text.
696692
//
697693
// - "group" is used when the node has children, irrespective of whether the
698694
// node is marked as a header or not. This is because marking a group
699695
// as a "heading" will prevent the AT from reaching its children.
696+
// - "heading" is used when the framework explicitly marks the node as a
697+
// heading and the node does not have children.
700698
// - If a node has a label and no children, assume is a paragraph of text.
701699
// In HTML text has no ARIA role. It's just a DOM node with text inside
702700
// it. Previously, role="text" was used, but it was only supported by
703701
// Safari, and it was removed starting Safari 17.
704702
if (semanticsObject.hasChildren) {
705703
labelAndValue!.preferredRepresentation = LabelRepresentation.ariaLabel;
706704
setAriaRole('group');
705+
} else if (semanticsObject.hasFlag(ui.SemanticsFlag.isHeader)) {
706+
labelAndValue!.preferredRepresentation = LabelRepresentation.domText;
707+
setAriaRole('heading');
707708
} else {
708709
labelAndValue!.preferredRepresentation = LabelRepresentation.sizedSpan;
709710
removeAttribute('role');
@@ -1271,24 +1272,11 @@ class SemanticsObject {
12711272
bool get isTextField => hasFlag(ui.SemanticsFlag.isTextField);
12721273

12731274
/// Whether this object represents a heading element.
1274-
///
1275-
/// Typically, a heading is a prominent piece of text that describes what the
1276-
/// rest of the screen or page is about.
1277-
///
1278-
/// Not to be confused with [isHeader].
12791275
bool get isHeading => headingLevel != 0;
12801276

1281-
/// Whether this object represents an interactive link.
1277+
/// Whether this object represents an editable text field.
12821278
bool get isLink => hasFlag(ui.SemanticsFlag.isLink);
12831279

1284-
/// Whether this object represents a header.
1285-
///
1286-
/// A header is a group of widgets that introduce the content of the screen
1287-
/// or a page.
1288-
///
1289-
/// Not to be confused with [isHeading].
1290-
bool get isHeader => hasFlag(ui.SemanticsFlag.isHeader);
1291-
12921280
/// Whether this object needs screen readers attention right away.
12931281
bool get isLiveRegion =>
12941282
hasFlag(ui.SemanticsFlag.isLiveRegion) &&
@@ -1702,8 +1690,6 @@ class SemanticsObject {
17021690
return SemanticRoleKind.route;
17031691
} else if (isLink) {
17041692
return SemanticRoleKind.link;
1705-
} else if (isHeader) {
1706-
return SemanticRoleKind.header;
17071693
} else {
17081694
return SemanticRoleKind.generic;
17091695
}
@@ -1721,7 +1707,6 @@ class SemanticsObject {
17211707
SemanticRoleKind.platformView => SemanticPlatformView(this),
17221708
SemanticRoleKind.link => SemanticLink(this),
17231709
SemanticRoleKind.heading => SemanticHeading(this),
1724-
SemanticRoleKind.header => SemanticHeader(this),
17251710
SemanticRoleKind.generic => GenericRole(this),
17261711
};
17271712
}

lib/web_ui/test/engine/semantics/semantics_test.dart

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -739,7 +739,7 @@ class MockSemanticsEnabler implements SemanticsEnabler {
739739
}
740740

741741
void _testHeader() {
742-
test('renders a header with a label and uses a sized span for label', () {
742+
test('renders heading role for headers', () {
743743
semantics()
744744
..debugOverrideTimestampFunction(() => _testTime)
745745
..semanticsEnabled = true;
@@ -755,13 +755,19 @@ void _testHeader() {
755755

756756
owner().updateSemantics(builder.build());
757757
expectSemanticsTree(owner(), '''
758-
<header><span>Header of the page</span></header>
758+
<sem role="heading">Header of the page</sem>
759759
''');
760760

761761
semantics().semanticsEnabled = false;
762762
});
763763

764-
test('renders a header with children and uses aria-label', () {
764+
// When a header has child elements, role="heading" prevents AT from reaching
765+
// child elements. To fix that role="group" is used, even though that causes
766+
// the heading to not be announced as a heading. If the app really needs the
767+
// heading to be announced as a heading, the developer can restructure the UI
768+
// such that the heading is not a parent node, but a side-note, e.g. preceding
769+
// the child list.
770+
test('uses group role for headers when children are present', () {
765771
semantics()
766772
..debugOverrideTimestampFunction(() => _testTime)
767773
..semanticsEnabled = true;
@@ -785,7 +791,7 @@ void _testHeader() {
785791

786792
owner().updateSemantics(builder.build());
787793
expectSemanticsTree(owner(), '''
788-
<header aria-label="Header of the page"><sem-c><sem></sem></sem-c></header>
794+
<sem role="group" aria-label="Header of the page"><sem-c><sem></sem></sem-c></sem>
789795
''');
790796

791797
semantics().semanticsEnabled = false;

0 commit comments

Comments
 (0)