🔤 Label in name

Common mistake

A common mistake is setting an accessible name that replaces the visible label entirely. For example, a button that reads “Buy now” on screen is given a semanticLabel of "Purchase item". Speech-input users who say “Buy now” to activate the button will be ignored, because the programmatic name no longer contains the visible text.

🎯 Relevant elements

This guideline applies to any interactive element that has a visible text label:

  • Buttons (ElevatedButton, TextButton, OutlinedButton)
  • Navigation items with visible text
  • Links and tappable text
  • Form fields with visible labels
  • Menu items

WCAG Guideline

This guideline is based on WCAG 2.2 — 2.5.3 Label in Name (Level A). When an interactive element has a visible text label, the accessible name must contain that visible text. This ensures that speech-input users who say the visible label can activate the control.


Solution

When adding or overriding a semantic label for an element that already has visible text, make sure the accessible name contains the visible text. It may include additional context, but must not omit or replace the visible label.

// ❌ Don't - accessible name replaces the visible label
ElevatedButton(
  onPressed: () => submitOrder(),
  child: Text('Buy now'),
);
// with:
Semantics(
  label: 'Purchase item',
  child: ElevatedButton(
    onPressed: () => submitOrder(),
    child: Text('Buy now'),
  ),
);

// ✅ Do - accessible name contains the visible text
Semantics(
  label: 'Buy now – 3 items in cart',
  child: ElevatedButton(
    onPressed: () => submitOrder(),
    child: Text('Buy now'),
  ),
);

// ✅ Do - no override needed; Flutter uses the Text widget's value automatically
ElevatedButton(
  onPressed: () => submitOrder(),
  child: Text('Buy now'),
);

Note: In most cases you don’t need to set a semanticLabel at all when a Text widget is present — Flutter derives the accessible name from it automatically. Only add a label when you need to provide extra context, and ensure the visible text is preserved in it.


Validation & Testing

See the Validation & Testing setup guide for tool configuration.

Manual screen reader testing

Enable TalkBack (Android) or VoiceOver (iOS) and navigate to each interactive element. Verify that the announced name matches or contains the visible text on screen.

flutter_test

testWidgets('button accessible name contains visible label', (tester) async {
  await tester.pumpWidget(MyWidget());

  final semantics = tester.getSemantics(find.text('Buy now'));
  expect(semantics.label, contains('Buy now'));
});

🛠️ Usage baseflow-a11y-components library

This is enforced on the following components:

  • A11yButton

This site uses Just the Docs, a documentation theme for Jekyll.