Hacktoberfest 2026: the issues maintainers tagged for October, open and beginner-friendly. Browse Hacktoberfest issues

[iOS] SnackBars on iOS show unusable and unnecessary Voice Control tag

Open Beginner friendly
#193,966 0 comments 0 reactions 0 assignees View on GitHub

Maintainers usually reply within 1 day

Nobody has claimed this yet.

Assessment

Difficulty
2/5
Estimated time
1-3 hours
Newbie friendliness
78/100
Issue type
Bug
Clarity
Clearly specified
Activity status
Active
Tech stack
dart, flutter, ios

Research direction

Start with packages/flutter/lib/src/material/snack_bar.dart, specifically _SnackBarState.build and the Semantics node shown in the issue. Check how dismissDirection relates to the onDismiss action, then look for or add a regression test covering Voice Control semantics for a SnackBar. Done when the unusable extra Voice Control tag is absent while the close button remains usable.

Written by the indexing model from the issue text.

Description

Steps to reproduce
  1. Create an app with a SnackBar and open it on an iOS device.
  2. Enable Voice Control (https://support.apple.com/en-us/111778)
  3. View the SnackBar
Expected results

The SnackBar should have just one Voice Control tag, which can be used to close the snackbar.

Actual results
Image

As seen in the image above, the SnackBar actually has two voice control tags. Tag '1' triggers no action, and it also should not be on the SnackBar. Tag '2' on the 'X' button is expected.

I suspect this is because in packages/flutter/lib/src/material/snack_bar.dart inside _SnackBarState.build, the Semantics node unconditionally assigns an onDismiss action for swipe-to-dismiss behavior on SnackBars, and Voice Control is adding a tag for this. However, this doesn't actually do anything since Voice Control performs a tap, not a swipe.

    snackBar = Semantics(
      container: true,
      liveRegion: true,
      onDismiss: () {
        ScaffoldMessenger.of(context).removeCurrentSnackBar(reason: SnackBarClosedReason.dismiss);
      },
      child: Dismissible(
        // ...
        direction: dismissDirection,
        child: snackBar,
      ),
    );

One potential fix would be omitting the onDismiss semantic action if dismissDirection is DismissDirection.none (I tried this locally and this seemed to fix the issue)

    snackBar = Semantics(
      container: true,
      liveRegion: true,
      onDismiss: dismissDirection == DismissDirection.none 
        ? null 
        : () {
            ScaffoldMessenger.of(context).removeCurrentSnackBar(reason: SnackBarClosedReason.dismiss);
          },
      // ...
Code sample
import 'package:flutter/material.dart';

final messengerKey = GlobalKey<ScaffoldMessengerState>();

void main() {
  runApp(MaterialApp(
    scaffoldMessengerKey: messengerKey,
    home: const Scaffold(),
  ));

  WidgetsBinding.instance.addPostFrameCallback((_) {
    messengerKey.currentState?.showSnackBar(
      SnackBar(
        behavior: SnackBarBehavior.fixed,
        dismissDirection: DismissDirection.down,
        content: const Text('Text'),
        action: SnackBarAction(label: 'X', onPressed: () {}),
        duration: const Duration(days: 365),
      ),
    );
  });
}
Screenshots or Video

See screenshot in "Actual results" section.

Logs

No response

Flutter Doctor output

N/A

Dominant language
Dart
Stars
179k
Forks
33.2k
Avg merge
2d 14h
Merged PRs (30d)
407

Getting set up

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

More from flutter/flutter

All issues in flutter/flutter

Similar issues

More Dart issues

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.