Repository navigation
MacOS - bug system sound on tap inside RouterOutlet #984
Description
Describe the bug
Title
System sound on tap inside RouterOutlet
Platform
Applicable only to macOS (my version 15.3.1).
Description
I encountered this issue while using modular with RouterOutlet in a new Flutter project. The RouterOutlet is placed inside the widget tree and occupies the remaining screen space using Expanded(child: RouterOutlet()), where nested navigation takes place. It’s also done this way in the official documentation.
However, depending on the widget inside the RouterOutlet, some parts of the RouterOutlet area become unexpectedly clickable with a sound effect. This also applies when there's another nested RouterOutlet inside it.
The behavior is inconsistent:
- Text('123') inside RouterOutlet is not clickable with a sound.
- Row(children: [Text('123')]) inside RouterOutlet is clickable with a sound, except for the text itself.
Using Flutter DevTools, I noticed that the clicks triggering the sound effect are intercepted by a Listener widget inside RouterOutlet. However, this was determined indirectly, as the trigger doesn’t always occur precisely on that widget.
I checked for similar issues in both modular and Flutter repositories but couldn’t find anything relevant.
Question
Is there a way to disable this sound effect? I couldn’t find any relevant settings or documentation on this.
Environment
Add your flutter doctor -v

Add your MainActivity
not applicable
Add your AndroidManifest.xml
not applicable
Add your /app/res/values/strings.xml
not applicable
To Reproduce
import 'package:flutter/material.dart';
import 'package:flutter_modular/flutter_modular.dart';
void main() {
runApp(ModularApp(module: AppModule(), child: AppWidget()));
}
class AppWidget extends StatelessWidget {
const AppWidget({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp.router(
theme: ThemeData(primarySwatch: Colors.blue),
routerConfig: Modular.routerConfig,
);
}
}
class AppModule extends Module {
AppModule();
@override
void routes(r){
r.child(
'/', child: (_) => HomePage(),children: [
ChildRoute('/text', child: (context) => Text('123')),
ChildRoute('/row', child: (context) => Row(children: [Text('123')],)),
ModuleRoute(SecondModule.route, module: SecondModule()),
],
transition: TransitionType.noTransition,
);
super.routes(r);
}
}
class HomePage extends StatelessWidget {
const HomePage({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
body: Row(
children: [
SizedBox(
width: 200,
child: Column(
children: [
InkWell(
child: Text('Text'),
onTap: () => Modular.to.navigate('/text'),
),
InkWell(
child: Text('Row'),
onTap: () => Modular.to.navigate('/row'),
),
InkWell(
child: Text('Submodule'),
onTap: () => Modular.to.navigate(SecondModule.route),
),
],
),
),
Container(width: 1, color: Colors.black),
Expanded(child: RouterOutlet()),
],
),
);
}
}
class SecondModule extends Module {
static const route = '/second';
@override
void binds(i) {}
@override
void routes(r) {
r.child('/', child: (context) => SecondPage(), children: [
ChildRoute('/text', child: (context) => Text('123')),
ChildRoute('/row', child: (context) => Row(children: [Text('123')],)),
]);
}
}
class SecondPage extends StatelessWidget {
const SecondPage({super.key});
@override
Widget build(BuildContext context) {
return Row(children: [
SizedBox(
width: 200,
child: Material(
child: Column(
children: [
InkWell(
child: Text('Text'),
onTap: () => Modular.to.navigate('${SecondModule.route}/text'),
),
InkWell(
child: Text('Row'),
onTap: () => Modular.to.navigate('${SecondModule.route}/row'),
),
],
),
)
),
Container(width: 1, color: Colors.black),
Expanded(child: RouterOutlet()),
]);
}
}
Expected behavior
Do not play unexpected system sound on mac os app
Screenshots
(turn on the sound on the video)



Activity
tspoke commentedon May 28, 2025
I have the exact same behaviour on Windows.
I found a way to prevent it for now :
jacobaraujo7 commentedon Jun 13, 2025
Fixed
alimardonbegov commentedon Jun 13, 2025
Hello! Thanks for replying!
Unfortunately, I still have the same issue.
Flutter doctor:
"
Running flutter doctor...
Doctor summary (to see all details, run flutter doctor -v):
[✓] Flutter (Channel stable, 3.32.4, on macOS 15.5 24F74 darwin-arm64, locale en-ME)
[✓] Android toolchain - develop for Android devices (Android SDK version 35.0.0)
[✓] Xcode - develop for iOS and macOS (Xcode 16.4)
[✓] Chrome - develop for the web
[✓] Android Studio (version 2024.1)
[✓] Connected device (2 available)
[✓] Network resources
• No issues found!
"
@jacobaraujo7 Is there a parameter I should use to avoid this, or is it supposed to disappear on its own?
Screen.Recording.2025-06-13.at.17.55.05.mov
tspoke commentedon Mar 19, 2026
I confirm the bug is still present on Modular v6.4.1.
Flutter 3.38.9 • channel stable • https://github.com/flutter/flutter.git
Framework • revision 67323de285 (7 weeks ago) • 2026-01-28 13:43:12 -0800
Engine • hash 5eb06b7ad5bb8cbc22c5230264c7a00ceac7674b (revision 587c18f873) (1 months ago) • 2026-01-27 23:23:03.000Z
Tools • Dart 3.10.8 • DevTools 2.51.1
tspoke commentedon Oct 9, 2026
Still present on v7.
Found the cause, and a workaround that covers every mouse button. The
GestureDetector(onTap: () {})workaround posted above only catches left clicks: right and middle clicks still beep.Cause
RouterOutletis a nestedNavigator, and every route in aNavigatoris built on top of aModalBarrier. For page routes that barrier is non-dismissible, and when a non-dismissible barrier is tapped Flutter callsSystemSound.play(SystemSoundType.alert)(seehandleDismissinwidgets/modal_barrier.dart). That is the alert beep on macOS andMessageBeepon Windows.A page that is not hit-test opaque lets the pointer through its empty areas, so the barrier underneath gets the tap. This explains the inconsistency in the report: a lone
Textfills the outlet and always claims the hit, whileRow(children: [Text])only claims it on the text itself. It also happens on root routes whose page leaves empty areas.Workaround
Make the page hit-test opaque so the tap never reaches the barrier.
Per page (v6 syntax shown):
Once for the whole app (v7), with a
PageTransition:Swap
TransitionType.nonefor.materialor.fadeas needed. Routes that declare their owntransition:need the same wrap.Tested on flutter_modular 7.1.1, Flutter 3.47.2, Windows. With
TransitionType.none, a tap on an empty area sendsSystemSound.playwithSystemSoundType.alerton the platform channel, for both a root page and an outlet page. With the wrap, left, right and middle clicks send nothing, and the page's own widgets still receive their taps. The per-page wrap relies on the same mechanism on v6, but I only ran it on v7.Possible fix in modular
Modular creates these pages itself (
_TransitionPageandRouterOutletState._pagein v7). Wrappingchildthere in an opaque hit-test widget, or returning a route whosebuildModalBarrier()does not beep, would fix it for everyone.