Skip to content

Conversation

@flutter-zl
Copy link
Contributor

@flutter-zl flutter-zl commented Jul 7, 2025

Description

Please check comment: #171040 (comment).

This PR adds SemanticsLabelBuilder, a new utility class for creating accessible concatenated labels with proper text direction handling and spacing. Currently, developers manually concatenate semantic labels using string interpolation, which is error-prone and leads to accessibility issues like missing spaces, incorrect text direction for RTL languages. The new builder provides automatic spacing, Unicode bidirectional text embedding for mixed LTR/RTL content.

Before (error-prone manual concatenation):

//  Missing space
String label = "$firstName$lastName";  // "JohnDoe"

String englishText = "Welcome";  
String arabicText = "مرحبا";     // Arabic "Hello"

// Manual Concatenation (WITHOUT Unicode embedding):
aria-label="Welcome 欢迎 مرحبا स्वागत है to our global app"
// Problem: Arabic does not have proper text direction handling

After (automatic and accessible):

Demo app after the change: https://label-0702.web.app/

// Automatic spacing and text direction handling
final label = (SemanticsLabelBuilder()
  ..addPart(firstName)
  ..addPart(lastName)).build();
// Result: "John Doe" with proper aria-label generation

// SemanticsLabelBuilder (WITH Unicode embedding):
aria-label="Welcome 欢迎 [U+202B]مرحبا[U+202C] स्वागत है to our global app"
//  Result: Arabic has proper text direction handling

Issues Fixed

This fixes #162094.

This PR addresses the general accessibility problem of error-prone manual label concatenation that affects screen reader users. While not fixing a specific filed issue, it provides a robust solution for the common pattern of building complex semantic labels that are critical for accessibility compliance, particularly for multilingual applications and complex UI components like contact cards, dashboards, and e-commerce listings.

Breaking Changes

No breaking changes were made. This is a purely additive API that doesn't modify existing behavior or require any migration.

Key Features Added

  • SemanticsLabelBuilder: Main builder class for concatenating text parts
  • Automatic spacing: Configurable separators with intelligent empty part handling
  • Text direction support: Unicode bidirectional embedding for RTL/LTR mixed content

Example Usage

// Basic usage
final label = (SemanticsLabelBuilder()
  ..addPart('Contact')
  ..addPart('John Doe')
  ..addPart('Phone: +1-555-0123')).build();
// Result: "Contact John Doe Phone: +1-555-0123"

// Custom separator
final label = (SemanticsLabelBuilder(separator: ', ')
  ..addPart('Name: Alice')
  ..addPart('Status: Online')).build();
// Result: "Name: Alice, Status: Online"

// Multilingual support
final label = (SemanticsLabelBuilder(textDirection: TextDirection.ltr)
  ..addPart('Welcome', textDirection: TextDirection.ltr)
  ..addPart('مرحبا', textDirection: TextDirection.rtl)
  ..addPart('to our app')).build();
// Result: "Welcome ‫مرحبا‬ to our app" (with proper RTL embedding)

## Pre-launch Checklist

- [x] I read the [Contributor Guide] and followed the process outlined there for submitting PRs.
- [x] I read the [Tree Hygiene] wiki page, which explains my responsibilities.
- [x] I read and followed the [Flutter Style Guide], including [Features we expect every widget to implement].
- [x] I signed the [CLA].
- [x] I listed at least one issue that this PR fixes in the description above.
- [x] I updated/added relevant documentation (doc comments with `///`).
- [x] I added new tests to check the change I am making, or this PR is [test-exempt].
- [x] I followed the [breaking change policy] and added [Data Driven Fixes] where supported.
- [x] All existing and new tests are passing.

…t direction support and comprehensive test suite
@github-actions github-actions bot added framework flutter/packages/flutter repository. See also f: labels. a: accessibility Accessibility, e.g. VoiceOver or TalkBack. (aka a11y) labels Jul 7, 2025
@flutter-zl flutter-zl requested review from mdebbar and yjbanov July 7, 2025 05:36
@flutter-zl flutter-zl marked this pull request as ready for review July 8, 2025 05:09
@flutter-zl flutter-zl mentioned this pull request Jul 8, 2025
9 tasks
@mdebbar
Copy link
Contributor

mdebbar commented Jul 8, 2025

//  Manual concatenation - confusing for screen readers without proper text direction handling
String label = "$englishText $arabicText";
// Result: "Welcome مرحبا" 
// Problem: Screen reader might read Arabic text incorrectly

I find this interesting (and surprising) and I'd like to learn more. Were you able to get the screen reader to read the Arabic text incorrectly?

@flutter-zl
Copy link
Contributor Author

//  Manual concatenation - confusing for screen readers without proper text direction handling
String label = "$englishText $arabicText";
// Result: "Welcome مرحبا" 
// Problem: Screen reader might read Arabic text incorrectly

I find this interesting (and surprising) and I'd like to learn more. Were you able to get the screen reader to read the Arabic text incorrectly?

The description is misleading. I updated the description. Arabic does not have proper text direction handling if developer does not handle carefully.

@flutter-zl flutter-zl enabled auto-merge July 10, 2025 17:34
@flutter-zl flutter-zl added this pull request to the merge queue Jul 11, 2025
Merged via the queue into flutter:master with commit ac6211a Jul 11, 2025
71 checks passed
@flutter-zl flutter-zl deleted the label_0707 branch July 11, 2025 19:34
justinmc pushed a commit to justinmc/flutter that referenced this pull request Jul 11, 2025
…#171683)

## Description

Please check comment:
flutter#171040 (comment).

This PR adds `SemanticsLabelBuilder`, a new utility class for creating
accessible concatenated labels with proper text direction handling and
spacing. Currently, developers manually concatenate semantic labels
using string interpolation, which is error-prone and leads to
accessibility issues like missing spaces, incorrect text direction for
RTL languages. The new builder provides automatic spacing, Unicode
bidirectional text embedding for mixed LTR/RTL content.

### Before (error-prone manual concatenation):
```dart
//  Missing space
String label = "$firstName$lastName";  // "JohnDoe"

String englishText = "Welcome";  
String arabicText = "مرحبا";     // Arabic "Hello"

// Manual Concatenation (WITHOUT Unicode embedding):
aria-label="Welcome 欢迎 مرحبا स्वागत है to our global app"
// Problem: Arabic does not have proper text direction handling
```

### After (automatic and accessible):

Demo app after the change: https://label-0702.web.app/

```dart
// Automatic spacing and text direction handling
final label = (SemanticsLabelBuilder()
  ..addPart(firstName)
  ..addPart(lastName)).build();
// Result: "John Doe" with proper aria-label generation

// SemanticsLabelBuilder (WITH Unicode embedding):
aria-label="Welcome 欢迎 [U+202B]مرحبا[U+202C] स्वागत है to our global app"
//  Result: Arabic has proper text direction handling
```

## Issues Fixed

This fixes flutter#162094. 

This PR addresses the general accessibility problem of error-prone
manual label concatenation that affects screen reader users. While not
fixing a specific filed issue, it provides a robust solution for the
common pattern of building complex semantic labels that are critical for
accessibility compliance, particularly for multilingual applications and
complex UI components like contact cards, dashboards, and e-commerce
listings.

## Breaking Changes

No breaking changes were made. This is a purely additive API that
doesn't modify existing behavior or require any migration.

## Key Features Added

- **SemanticsLabelBuilder**: Main builder class for concatenating text
parts
- **Automatic spacing**: Configurable separators with intelligent empty
part handling
- **Text direction support**: Unicode bidirectional embedding for
RTL/LTR mixed content

## Example Usage

```dart
// Basic usage
final label = (SemanticsLabelBuilder()
  ..addPart('Contact')
  ..addPart('John Doe')
  ..addPart('Phone: +1-555-0123')).build();
// Result: "Contact John Doe Phone: +1-555-0123"

// Custom separator
final label = (SemanticsLabelBuilder(separator: ', ')
  ..addPart('Name: Alice')
  ..addPart('Status: Online')).build();
// Result: "Name: Alice, Status: Online"

// Multilingual support
final label = (SemanticsLabelBuilder(textDirection: TextDirection.ltr)
  ..addPart('Welcome', textDirection: TextDirection.ltr)
  ..addPart('مرحبا', textDirection: TextDirection.rtl)
  ..addPart('to our app')).build();
// Result: "Welcome ‫مرحبا‬ to our app" (with proper RTL embedding)
```
```

## Pre-launch Checklist

- [x] I read the [Contributor Guide] and followed the process outlined there for submitting PRs.
- [x] I read the [Tree Hygiene] wiki page, which explains my responsibilities.
- [x] I read and followed the [Flutter Style Guide], including [Features we expect every widget to implement].
- [x] I signed the [CLA].
- [x] I listed at least one issue that this PR fixes in the description above.
- [x] I updated/added relevant documentation (doc comments with `///`).
- [x] I added new tests to check the change I am making, or this PR is [test-exempt].
- [x] I followed the [breaking change policy] and added [Data Driven Fixes] where supported.
- [x] All existing and new tests are passing.

---------

Co-authored-by: Mouad Debbar <[email protected]>
engine-flutter-autoroll added a commit to engine-flutter-autoroll/packages that referenced this pull request Jul 12, 2025
auto-submit bot pushed a commit to flutter/packages that referenced this pull request Jul 12, 2025
Roll Flutter from 43657f3baa17 to 35f197f1e5f5 (39 revisions)

flutter/flutter@43657f3...35f197f

2025-07-12 [email protected] Roll Fuchsia Linux SDK from 8aoEy1hp2a9HI1pt-... to xQlbHCUI33kDvkew8... (flutter/flutter#172060)
2025-07-12 [email protected] Add RSuperellipse support to Web (global cache) (flutter/flutter#171489)
2025-07-12 [email protected] Fix grammar: Change 'A' to 'An' before IOSSystemContextMenuItemData (flutter/flutter#172019)
2025-07-11 [email protected] Manual roll Dart to b21dca1b89ff (flutter/flutter#172038)
2025-07-11 [email protected] Roll Skia from 2ea2ba09ef85 to 92354f64e37f (1 revision) (flutter/flutter#172039)
2025-07-11 [email protected] Fix CheckedPopupMenuItem semantics to use menuItemCheckbox role with checked state (flutter/flutter#171749)
2025-07-11 [email protected] adds gemini.md to `engine` and `licenses_cpp` (flutter/flutter#172022)
2025-07-11 [email protected] [Web] Implement disabling interactive selection (flutter/flutter#171935)
2025-07-11 [email protected] [tool] Make google3 have to override feature flags (flutter/flutter#171933)
2025-07-11 [email protected] License cpp 710 (flutter/flutter#171989)
2025-07-11 [email protected] add content description to tooltip-only nodes for android (flutter/flutter#171541)
2025-07-11 [email protected] [Web a11y]Update table cell to use LabelRepresentation.sizedSpan  (flutter/flutter#172013)
2025-07-11 [email protected] [ Tool ] Enable `omit_obvious_*_types` and `specify_nonobvious_*_types` lints (flutter/flutter#172018)
2025-07-11 [email protected] Add SemanticsLabelBuilder for Accessible Label Concatenation (flutter/flutter#171683)
2025-07-11 [email protected] Run tests on either macOS 14 or 15 (flutter/flutter#171076)
2025-07-11 [email protected] Roll Skia from db1a5550c848 to 2ea2ba09ef85 (1 revision) (flutter/flutter#172017)
2025-07-11 [email protected] [Cupertino] Make some widgets no longer use RSuperellipse (flutter/flutter#171830)
2025-07-11 [email protected] Detach the resource context from the IO thread only if the shell's IO manager is no longer being used by any other spawned shells (flutter/flutter#171554)
2025-07-11 [email protected] Started querying the app state for the gpu disabled sync switch (flutter/flutter#171785)
2025-07-11 [email protected] License_cpp 7/02 (flutter/flutter#171558)
2025-07-11 [email protected] [web] Refactor clipboard. (flutter/flutter#171427)
2025-07-11 [email protected] Require 64-bit Windows (flutter/flutter#171925)
2025-07-11 [email protected] Run hot_reload_with_asset_web_test.dart on Mac/Windows (flutter/flutter#171280)
2025-07-11 [email protected] Roll Skia from da7e3eae7c2b to db1a5550c848 (2 revisions) (flutter/flutter#171999)
2025-07-11 [email protected] Roll Skia from 26571c3b1771 to da7e3eae7c2b (2 revisions) (flutter/flutter#171997)
2025-07-11 [email protected] Roll Skia from 34a40032ff0a to 26571c3b1771 (1 revision) (flutter/flutter#171995)
2025-07-11 [email protected] Roll Fuchsia Linux SDK from lO64ePNEGrGzs-MFC... to 8aoEy1hp2a9HI1pt-... (flutter/flutter#171993)
2025-07-10 [email protected] Remove redundant ThemeData(useMaterial3: true) from tests (flutter/flutter#171569)
2025-07-10 [email protected] [Android 16] Updated linux_android_emu to a 36 AVD in framework CI (flutter/flutter#169121)
2025-07-10 [email protected] [iOS] Add Live Text option to system context menu (flutter/flutter#170969)
2025-07-10 [email protected] Roll Skia from dc3da09ca905 to 34a40032ff0a (1 revision) (flutter/flutter#171982)
2025-07-10 [email protected] feat: Expose FocusNode of FocusTraversalGroup (flutter/flutter#171979)
2025-07-10 [email protected] `CupertinoDatePicker` and `CupertinoTimerPicker` new onChanged behavior (flutter/flutter#170793)
2025-07-10 [email protected] Manual roll Dart SDK from 8d69b07b9d9d to 07ea3aaaadf0 (32 revisions) (flutter/flutter#171969)
2025-07-10 [email protected] Style: Rename pageBuilder with builder in showCupertinoSheet (flutter/flutter#170625)
2025-07-10 [email protected] Roll Skia from bdb8bfcde7f3 to dc3da09ca905 (3 revisions) (flutter/flutter#171971)
2025-07-10 [email protected] Feat: Add foreground color for cupertino button (flutter/flutter#170898)
2025-07-10 [email protected] Roll Skia from 0fef076beec3 to bdb8bfcde7f3 (34 revisions) (flutter/flutter#171964)
2025-07-10 [email protected] Run stateless_stateful_hot_reload_web_test.dart on Mac/Windows (flutter/flutter#171283)

If this roll has caused a breakage, revert this CL and stop the roller
using the controls here:
https://autoroll.skia.org/r/flutter-packages
Please CC [email protected],[email protected] on the revert to ensure that a human
is aware of the problem.

...
azatech pushed a commit to azatech/flutter that referenced this pull request Jul 28, 2025
…#171683)

## Description

Please check comment:
flutter#171040 (comment).

This PR adds `SemanticsLabelBuilder`, a new utility class for creating
accessible concatenated labels with proper text direction handling and
spacing. Currently, developers manually concatenate semantic labels
using string interpolation, which is error-prone and leads to
accessibility issues like missing spaces, incorrect text direction for
RTL languages. The new builder provides automatic spacing, Unicode
bidirectional text embedding for mixed LTR/RTL content.

### Before (error-prone manual concatenation):
```dart
//  Missing space
String label = "$firstName$lastName";  // "JohnDoe"

String englishText = "Welcome";  
String arabicText = "مرحبا";     // Arabic "Hello"

// Manual Concatenation (WITHOUT Unicode embedding):
aria-label="Welcome 欢迎 مرحبا स्वागत है to our global app"
// Problem: Arabic does not have proper text direction handling
```

### After (automatic and accessible):

Demo app after the change: https://label-0702.web.app/

```dart
// Automatic spacing and text direction handling
final label = (SemanticsLabelBuilder()
  ..addPart(firstName)
  ..addPart(lastName)).build();
// Result: "John Doe" with proper aria-label generation

// SemanticsLabelBuilder (WITH Unicode embedding):
aria-label="Welcome 欢迎 [U+202B]مرحبا[U+202C] स्वागत है to our global app"
//  Result: Arabic has proper text direction handling
```

## Issues Fixed

This fixes flutter#162094. 

This PR addresses the general accessibility problem of error-prone
manual label concatenation that affects screen reader users. While not
fixing a specific filed issue, it provides a robust solution for the
common pattern of building complex semantic labels that are critical for
accessibility compliance, particularly for multilingual applications and
complex UI components like contact cards, dashboards, and e-commerce
listings.

## Breaking Changes

No breaking changes were made. This is a purely additive API that
doesn't modify existing behavior or require any migration.

## Key Features Added

- **SemanticsLabelBuilder**: Main builder class for concatenating text
parts
- **Automatic spacing**: Configurable separators with intelligent empty
part handling
- **Text direction support**: Unicode bidirectional embedding for
RTL/LTR mixed content

## Example Usage

```dart
// Basic usage
final label = (SemanticsLabelBuilder()
  ..addPart('Contact')
  ..addPart('John Doe')
  ..addPart('Phone: +1-555-0123')).build();
// Result: "Contact John Doe Phone: +1-555-0123"

// Custom separator
final label = (SemanticsLabelBuilder(separator: ', ')
  ..addPart('Name: Alice')
  ..addPart('Status: Online')).build();
// Result: "Name: Alice, Status: Online"

// Multilingual support
final label = (SemanticsLabelBuilder(textDirection: TextDirection.ltr)
  ..addPart('Welcome', textDirection: TextDirection.ltr)
  ..addPart('مرحبا', textDirection: TextDirection.rtl)
  ..addPart('to our app')).build();
// Result: "Welcome ‫مرحبا‬ to our app" (with proper RTL embedding)
```
```

## Pre-launch Checklist

- [x] I read the [Contributor Guide] and followed the process outlined there for submitting PRs.
- [x] I read the [Tree Hygiene] wiki page, which explains my responsibilities.
- [x] I read and followed the [Flutter Style Guide], including [Features we expect every widget to implement].
- [x] I signed the [CLA].
- [x] I listed at least one issue that this PR fixes in the description above.
- [x] I updated/added relevant documentation (doc comments with `///`).
- [x] I added new tests to check the change I am making, or this PR is [test-exempt].
- [x] I followed the [breaking change policy] and added [Data Driven Fixes] where supported.
- [x] All existing and new tests are passing.

---------

Co-authored-by: Mouad Debbar <[email protected]>
vashworth pushed a commit to vashworth/packages that referenced this pull request Jul 30, 2025
…r#9602)

Roll Flutter from 43657f3baa17 to 35f197f1e5f5 (39 revisions)

flutter/flutter@43657f3...35f197f

2025-07-12 [email protected] Roll Fuchsia Linux SDK from 8aoEy1hp2a9HI1pt-... to xQlbHCUI33kDvkew8... (flutter/flutter#172060)
2025-07-12 [email protected] Add RSuperellipse support to Web (global cache) (flutter/flutter#171489)
2025-07-12 [email protected] Fix grammar: Change 'A' to 'An' before IOSSystemContextMenuItemData (flutter/flutter#172019)
2025-07-11 [email protected] Manual roll Dart to b21dca1b89ff (flutter/flutter#172038)
2025-07-11 [email protected] Roll Skia from 2ea2ba09ef85 to 92354f64e37f (1 revision) (flutter/flutter#172039)
2025-07-11 [email protected] Fix CheckedPopupMenuItem semantics to use menuItemCheckbox role with checked state (flutter/flutter#171749)
2025-07-11 [email protected] adds gemini.md to `engine` and `licenses_cpp` (flutter/flutter#172022)
2025-07-11 [email protected] [Web] Implement disabling interactive selection (flutter/flutter#171935)
2025-07-11 [email protected] [tool] Make google3 have to override feature flags (flutter/flutter#171933)
2025-07-11 [email protected] License cpp 710 (flutter/flutter#171989)
2025-07-11 [email protected] add content description to tooltip-only nodes for android (flutter/flutter#171541)
2025-07-11 [email protected] [Web a11y]Update table cell to use LabelRepresentation.sizedSpan  (flutter/flutter#172013)
2025-07-11 [email protected] [ Tool ] Enable `omit_obvious_*_types` and `specify_nonobvious_*_types` lints (flutter/flutter#172018)
2025-07-11 [email protected] Add SemanticsLabelBuilder for Accessible Label Concatenation (flutter/flutter#171683)
2025-07-11 [email protected] Run tests on either macOS 14 or 15 (flutter/flutter#171076)
2025-07-11 [email protected] Roll Skia from db1a5550c848 to 2ea2ba09ef85 (1 revision) (flutter/flutter#172017)
2025-07-11 [email protected] [Cupertino] Make some widgets no longer use RSuperellipse (flutter/flutter#171830)
2025-07-11 [email protected] Detach the resource context from the IO thread only if the shell's IO manager is no longer being used by any other spawned shells (flutter/flutter#171554)
2025-07-11 [email protected] Started querying the app state for the gpu disabled sync switch (flutter/flutter#171785)
2025-07-11 [email protected] License_cpp 7/02 (flutter/flutter#171558)
2025-07-11 [email protected] [web] Refactor clipboard. (flutter/flutter#171427)
2025-07-11 [email protected] Require 64-bit Windows (flutter/flutter#171925)
2025-07-11 [email protected] Run hot_reload_with_asset_web_test.dart on Mac/Windows (flutter/flutter#171280)
2025-07-11 [email protected] Roll Skia from da7e3eae7c2b to db1a5550c848 (2 revisions) (flutter/flutter#171999)
2025-07-11 [email protected] Roll Skia from 26571c3b1771 to da7e3eae7c2b (2 revisions) (flutter/flutter#171997)
2025-07-11 [email protected] Roll Skia from 34a40032ff0a to 26571c3b1771 (1 revision) (flutter/flutter#171995)
2025-07-11 [email protected] Roll Fuchsia Linux SDK from lO64ePNEGrGzs-MFC... to 8aoEy1hp2a9HI1pt-... (flutter/flutter#171993)
2025-07-10 [email protected] Remove redundant ThemeData(useMaterial3: true) from tests (flutter/flutter#171569)
2025-07-10 [email protected] [Android 16] Updated linux_android_emu to a 36 AVD in framework CI (flutter/flutter#169121)
2025-07-10 [email protected] [iOS] Add Live Text option to system context menu (flutter/flutter#170969)
2025-07-10 [email protected] Roll Skia from dc3da09ca905 to 34a40032ff0a (1 revision) (flutter/flutter#171982)
2025-07-10 [email protected] feat: Expose FocusNode of FocusTraversalGroup (flutter/flutter#171979)
2025-07-10 [email protected] `CupertinoDatePicker` and `CupertinoTimerPicker` new onChanged behavior (flutter/flutter#170793)
2025-07-10 [email protected] Manual roll Dart SDK from 8d69b07b9d9d to 07ea3aaaadf0 (32 revisions) (flutter/flutter#171969)
2025-07-10 [email protected] Style: Rename pageBuilder with builder in showCupertinoSheet (flutter/flutter#170625)
2025-07-10 [email protected] Roll Skia from bdb8bfcde7f3 to dc3da09ca905 (3 revisions) (flutter/flutter#171971)
2025-07-10 [email protected] Feat: Add foreground color for cupertino button (flutter/flutter#170898)
2025-07-10 [email protected] Roll Skia from 0fef076beec3 to bdb8bfcde7f3 (34 revisions) (flutter/flutter#171964)
2025-07-10 [email protected] Run stateless_stateful_hot_reload_web_test.dart on Mac/Windows (flutter/flutter#171283)

If this roll has caused a breakage, revert this CL and stop the roller
using the controls here:
https://autoroll.skia.org/r/flutter-packages
Please CC [email protected],[email protected] on the revert to ensure that a human
is aware of the problem.

...
engine-flutter-autoroll added a commit to engine-flutter-autoroll/packages that referenced this pull request Aug 14, 2025
engine-flutter-autoroll added a commit to engine-flutter-autoroll/packages that referenced this pull request Aug 14, 2025
engine-flutter-autoroll added a commit to engine-flutter-autoroll/packages that referenced this pull request Aug 15, 2025
engine-flutter-autoroll added a commit to engine-flutter-autoroll/packages that referenced this pull request Aug 15, 2025
engine-flutter-autoroll added a commit to engine-flutter-autoroll/packages that referenced this pull request Aug 16, 2025
ksokolovskyi pushed a commit to ksokolovskyi/flutter that referenced this pull request Aug 19, 2025
…#171683)

## Description

Please check comment:
flutter#171040 (comment).

This PR adds `SemanticsLabelBuilder`, a new utility class for creating
accessible concatenated labels with proper text direction handling and
spacing. Currently, developers manually concatenate semantic labels
using string interpolation, which is error-prone and leads to
accessibility issues like missing spaces, incorrect text direction for
RTL languages. The new builder provides automatic spacing, Unicode
bidirectional text embedding for mixed LTR/RTL content.

### Before (error-prone manual concatenation):
```dart
//  Missing space
String label = "$firstName$lastName";  // "JohnDoe"

String englishText = "Welcome";  
String arabicText = "مرحبا";     // Arabic "Hello"

// Manual Concatenation (WITHOUT Unicode embedding):
aria-label="Welcome 欢迎 مرحبا स्वागत है to our global app"
// Problem: Arabic does not have proper text direction handling
```

### After (automatic and accessible):

Demo app after the change: https://label-0702.web.app/

```dart
// Automatic spacing and text direction handling
final label = (SemanticsLabelBuilder()
  ..addPart(firstName)
  ..addPart(lastName)).build();
// Result: "John Doe" with proper aria-label generation

// SemanticsLabelBuilder (WITH Unicode embedding):
aria-label="Welcome 欢迎 [U+202B]مرحبا[U+202C] स्वागत है to our global app"
//  Result: Arabic has proper text direction handling
```

## Issues Fixed

This fixes flutter#162094. 

This PR addresses the general accessibility problem of error-prone
manual label concatenation that affects screen reader users. While not
fixing a specific filed issue, it provides a robust solution for the
common pattern of building complex semantic labels that are critical for
accessibility compliance, particularly for multilingual applications and
complex UI components like contact cards, dashboards, and e-commerce
listings.

## Breaking Changes

No breaking changes were made. This is a purely additive API that
doesn't modify existing behavior or require any migration.

## Key Features Added

- **SemanticsLabelBuilder**: Main builder class for concatenating text
parts
- **Automatic spacing**: Configurable separators with intelligent empty
part handling
- **Text direction support**: Unicode bidirectional embedding for
RTL/LTR mixed content

## Example Usage

```dart
// Basic usage
final label = (SemanticsLabelBuilder()
  ..addPart('Contact')
  ..addPart('John Doe')
  ..addPart('Phone: +1-555-0123')).build();
// Result: "Contact John Doe Phone: +1-555-0123"

// Custom separator
final label = (SemanticsLabelBuilder(separator: ', ')
  ..addPart('Name: Alice')
  ..addPart('Status: Online')).build();
// Result: "Name: Alice, Status: Online"

// Multilingual support
final label = (SemanticsLabelBuilder(textDirection: TextDirection.ltr)
  ..addPart('Welcome', textDirection: TextDirection.ltr)
  ..addPart('مرحبا', textDirection: TextDirection.rtl)
  ..addPart('to our app')).build();
// Result: "Welcome ‫مرحبا‬ to our app" (with proper RTL embedding)
```
```

## Pre-launch Checklist

- [x] I read the [Contributor Guide] and followed the process outlined there for submitting PRs.
- [x] I read the [Tree Hygiene] wiki page, which explains my responsibilities.
- [x] I read and followed the [Flutter Style Guide], including [Features we expect every widget to implement].
- [x] I signed the [CLA].
- [x] I listed at least one issue that this PR fixes in the description above.
- [x] I updated/added relevant documentation (doc comments with `///`).
- [x] I added new tests to check the change I am making, or this PR is [test-exempt].
- [x] I followed the [breaking change policy] and added [Data Driven Fixes] where supported.
- [x] All existing and new tests are passing.

---------

Co-authored-by: Mouad Debbar <[email protected]>
mboetger pushed a commit to mboetger/flutter that referenced this pull request Sep 18, 2025
…#171683)

## Description

Please check comment:
flutter#171040 (comment).

This PR adds `SemanticsLabelBuilder`, a new utility class for creating
accessible concatenated labels with proper text direction handling and
spacing. Currently, developers manually concatenate semantic labels
using string interpolation, which is error-prone and leads to
accessibility issues like missing spaces, incorrect text direction for
RTL languages. The new builder provides automatic spacing, Unicode
bidirectional text embedding for mixed LTR/RTL content.

### Before (error-prone manual concatenation):
```dart
//  Missing space
String label = "$firstName$lastName";  // "JohnDoe"

String englishText = "Welcome";  
String arabicText = "مرحبا";     // Arabic "Hello"

// Manual Concatenation (WITHOUT Unicode embedding):
aria-label="Welcome 欢迎 مرحبا स्वागत है to our global app"
// Problem: Arabic does not have proper text direction handling
```

### After (automatic and accessible):

Demo app after the change: https://label-0702.web.app/

```dart
// Automatic spacing and text direction handling
final label = (SemanticsLabelBuilder()
  ..addPart(firstName)
  ..addPart(lastName)).build();
// Result: "John Doe" with proper aria-label generation

// SemanticsLabelBuilder (WITH Unicode embedding):
aria-label="Welcome 欢迎 [U+202B]مرحبا[U+202C] स्वागत है to our global app"
//  Result: Arabic has proper text direction handling
```

## Issues Fixed

This fixes flutter#162094. 

This PR addresses the general accessibility problem of error-prone
manual label concatenation that affects screen reader users. While not
fixing a specific filed issue, it provides a robust solution for the
common pattern of building complex semantic labels that are critical for
accessibility compliance, particularly for multilingual applications and
complex UI components like contact cards, dashboards, and e-commerce
listings.

## Breaking Changes

No breaking changes were made. This is a purely additive API that
doesn't modify existing behavior or require any migration.

## Key Features Added

- **SemanticsLabelBuilder**: Main builder class for concatenating text
parts
- **Automatic spacing**: Configurable separators with intelligent empty
part handling
- **Text direction support**: Unicode bidirectional embedding for
RTL/LTR mixed content

## Example Usage

```dart
// Basic usage
final label = (SemanticsLabelBuilder()
  ..addPart('Contact')
  ..addPart('John Doe')
  ..addPart('Phone: +1-555-0123')).build();
// Result: "Contact John Doe Phone: +1-555-0123"

// Custom separator
final label = (SemanticsLabelBuilder(separator: ', ')
  ..addPart('Name: Alice')
  ..addPart('Status: Online')).build();
// Result: "Name: Alice, Status: Online"

// Multilingual support
final label = (SemanticsLabelBuilder(textDirection: TextDirection.ltr)
  ..addPart('Welcome', textDirection: TextDirection.ltr)
  ..addPart('مرحبا', textDirection: TextDirection.rtl)
  ..addPart('to our app')).build();
// Result: "Welcome ‫مرحبا‬ to our app" (with proper RTL embedding)
```
```

## Pre-launch Checklist

- [x] I read the [Contributor Guide] and followed the process outlined there for submitting PRs.
- [x] I read the [Tree Hygiene] wiki page, which explains my responsibilities.
- [x] I read and followed the [Flutter Style Guide], including [Features we expect every widget to implement].
- [x] I signed the [CLA].
- [x] I listed at least one issue that this PR fixes in the description above.
- [x] I updated/added relevant documentation (doc comments with `///`).
- [x] I added new tests to check the change I am making, or this PR is [test-exempt].
- [x] I followed the [breaking change policy] and added [Data Driven Fixes] where supported.
- [x] All existing and new tests are passing.

---------

Co-authored-by: Mouad Debbar <[email protected]>
lucaantonelli pushed a commit to lucaantonelli/flutter that referenced this pull request Nov 21, 2025
…#171683)

## Description

Please check comment:
flutter#171040 (comment).

This PR adds `SemanticsLabelBuilder`, a new utility class for creating
accessible concatenated labels with proper text direction handling and
spacing. Currently, developers manually concatenate semantic labels
using string interpolation, which is error-prone and leads to
accessibility issues like missing spaces, incorrect text direction for
RTL languages. The new builder provides automatic spacing, Unicode
bidirectional text embedding for mixed LTR/RTL content.

### Before (error-prone manual concatenation):
```dart
//  Missing space
String label = "$firstName$lastName";  // "JohnDoe"

String englishText = "Welcome";  
String arabicText = "مرحبا";     // Arabic "Hello"

// Manual Concatenation (WITHOUT Unicode embedding):
aria-label="Welcome 欢迎 مرحبا स्वागत है to our global app"
// Problem: Arabic does not have proper text direction handling
```

### After (automatic and accessible):

Demo app after the change: https://label-0702.web.app/

```dart
// Automatic spacing and text direction handling
final label = (SemanticsLabelBuilder()
  ..addPart(firstName)
  ..addPart(lastName)).build();
// Result: "John Doe" with proper aria-label generation

// SemanticsLabelBuilder (WITH Unicode embedding):
aria-label="Welcome 欢迎 [U+202B]مرحبا[U+202C] स्वागत है to our global app"
//  Result: Arabic has proper text direction handling
```

## Issues Fixed

This fixes flutter#162094. 

This PR addresses the general accessibility problem of error-prone
manual label concatenation that affects screen reader users. While not
fixing a specific filed issue, it provides a robust solution for the
common pattern of building complex semantic labels that are critical for
accessibility compliance, particularly for multilingual applications and
complex UI components like contact cards, dashboards, and e-commerce
listings.

## Breaking Changes

No breaking changes were made. This is a purely additive API that
doesn't modify existing behavior or require any migration.

## Key Features Added

- **SemanticsLabelBuilder**: Main builder class for concatenating text
parts
- **Automatic spacing**: Configurable separators with intelligent empty
part handling
- **Text direction support**: Unicode bidirectional embedding for
RTL/LTR mixed content

## Example Usage

```dart
// Basic usage
final label = (SemanticsLabelBuilder()
  ..addPart('Contact')
  ..addPart('John Doe')
  ..addPart('Phone: +1-555-0123')).build();
// Result: "Contact John Doe Phone: +1-555-0123"

// Custom separator
final label = (SemanticsLabelBuilder(separator: ', ')
  ..addPart('Name: Alice')
  ..addPart('Status: Online')).build();
// Result: "Name: Alice, Status: Online"

// Multilingual support
final label = (SemanticsLabelBuilder(textDirection: TextDirection.ltr)
  ..addPart('Welcome', textDirection: TextDirection.ltr)
  ..addPart('مرحبا', textDirection: TextDirection.rtl)
  ..addPart('to our app')).build();
// Result: "Welcome ‫مرحبا‬ to our app" (with proper RTL embedding)
```
```

## Pre-launch Checklist

- [x] I read the [Contributor Guide] and followed the process outlined there for submitting PRs.
- [x] I read the [Tree Hygiene] wiki page, which explains my responsibilities.
- [x] I read and followed the [Flutter Style Guide], including [Features we expect every widget to implement].
- [x] I signed the [CLA].
- [x] I listed at least one issue that this PR fixes in the description above.
- [x] I updated/added relevant documentation (doc comments with `///`).
- [x] I added new tests to check the change I am making, or this PR is [test-exempt].
- [x] I followed the [breaking change policy] and added [Data Driven Fixes] where supported.
- [x] All existing and new tests are passing.

---------

Co-authored-by: Mouad Debbar <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

a: accessibility Accessibility, e.g. VoiceOver or TalkBack. (aka a11y) framework flutter/packages/flutter repository. See also f: labels.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Flutter Web: aria-labelledby must be an available property on all component types (Accessibility)

2 participants