Skip to content

[go_router] SelectionArea dead zones after ShellRoute navigation — offstage page selectables intercept drag events #182573

Open

Description

@davidmigloz

What package does this bug report belong to?

go_router

What target platforms are you seeing this bug on?

Web

Have you already upgraded your packages?

Yes

Dependency versions

pubspec.lock
  # Generated by pub                                                                                                                   
  # See https://dart.dev/tools/pub/glossary#lockfile                                                                                   
  packages:                                                                                                                            
    async:                                                                                                                             
      dependency: transitive                                                         
      description:
        name: async
        sha256: "758e6d74e971c3e5aceb4110bfd6698efc7f501675bcfe0c775459a8140750eb"
        url: "https://pub.dev"
      source: hosted
      version: "2.13.0"
    boolean_selector:
      dependency: transitive
      description:
        name: boolean_selector
        sha256: "8aab1771e1243a5063b8b0ff68042d67334e3feab9e95b9490f9a6ebf73b42ea"
        url: "https://pub.dev"
      source: hosted
      version: "2.1.2"
    characters:
      dependency: transitive
      description:
        name: characters
        sha256: faf38497bda5ead2a8c7615f4f7939df04333478bf32e4173fcb06d428b5716b
        url: "https://pub.dev"
      source: hosted
      version: "1.4.1"
    clock:
      dependency: transitive
      description:
        name: clock
        sha256: fddb70d9b5277016c77a80201021d40a2247104d9f4aa7bab7157b7e3f05b84b
        url: "https://pub.dev"
      source: hosted
      version: "1.1.2"
    collection:
      dependency: transitive
      description:
        name: collection
        sha256: "2f5709ae4d3d59dd8f7cd309b4e023046b57d8a6c82130785d2b0e5868084e76"
        url: "https://pub.dev"
      source: hosted
      version: "1.19.1"
    fake_async:
      dependency: transitive
      description:
        name: fake_async
        sha256: "5368f224a74523e8d2e7399ea1638b37aecfca824a3cc4dfdf77bf1fa905ac44"
        url: "https://pub.dev"
      source: hosted
      version: "1.3.3"
    flutter:
      dependency: "direct main"
      description: flutter
      source: sdk
      version: "0.0.0"
    flutter_lints:
      dependency: "direct dev"
      description:
        name: flutter_lints
        sha256: "3105dc8492f6183fb076ccf1f351ac3d60564bff92e20bfc4af9cc1651f4e7e1"
        url: "https://pub.dev"
      source: hosted
      version: "6.0.0"
    flutter_test:
      dependency: "direct dev"
      description: flutter
      source: sdk
      version: "0.0.0"
    flutter_web_plugins:
      dependency: transitive
      description: flutter
      source: sdk
      version: "0.0.0"
    go_router:
      dependency: "direct main"
      description:
        name: go_router
        sha256: "7974313e217a7771557add6ff2238acb63f635317c35fa590d348fb238f00896"
        url: "https://pub.dev"
      source: hosted
      version: "17.1.0"
    leak_tracker:
      dependency: transitive
      description:
        name: leak_tracker
        sha256: "33e2e26bdd85a0112ec15400c8cbffea70d0f9c3407491f672a2fad47915e2de"
        url: "https://pub.dev"
      source: hosted
      version: "11.0.2"
    leak_tracker_flutter_testing:
      dependency: transitive
      description:
        name: leak_tracker_flutter_testing
        sha256: "1dbc140bb5a23c75ea9c4811222756104fbcd1a27173f0c34ca01e16bea473c1"
        url: "https://pub.dev"
      source: hosted
      version: "3.0.10"
    leak_tracker_testing:
      dependency: transitive
      description:
        name: leak_tracker_testing
        sha256: "8d5a2d49f4a66b49744b23b018848400d23e54caf9463f4eb20df3eb8acb2eb1"
        url: "https://pub.dev"
      source: hosted
      version: "3.0.2"
    lints:
      dependency: transitive
      description:
        name: lints
        sha256: "12f842a479589fea194fe5c5a3095abc7be0c1f2ddfa9a0e76aed1dbd26a87df"
        url: "https://pub.dev"
      source: hosted
      version: "6.1.0"
    logging:
      dependency: transitive
      description:
        name: logging
        sha256: c8245ada5f1717ed44271ed1c26b8ce85ca3228fd2ffdb75468ab01979309d61
        url: "https://pub.dev"
      source: hosted
      version: "1.3.0"
    matcher:
      dependency: transitive
      description:
        name: matcher
        sha256: "12956d0ad8390bbcc63ca2e1469c0619946ccb52809807067a7020d57e647aa6"
        url: "https://pub.dev"
      source: hosted
      version: "0.12.18"
    material_color_utilities:
      dependency: transitive
      description:
        name: material_color_utilities
        sha256: "9c337007e82b1889149c82ed242ed1cb24a66044e30979c44912381e9be4c48b"
        url: "https://pub.dev"
      source: hosted
      version: "0.13.0"
    meta:
      dependency: transitive
      description:
        name: meta
        sha256: "23f08335362185a5ea2ad3a4e597f1375e78bce8a040df5c600c8d3552ef2394"
        url: "https://pub.dev"
      source: hosted
      version: "1.17.0"
    path:
      dependency: transitive
      description:
        name: path
        sha256: "75cca69d1490965be98c73ceaea117e8a04dd21217b37b292c9ddbec0d955bc5"
        url: "https://pub.dev"
      source: hosted
      version: "1.9.1"
    sky_engine:
      dependency: transitive
      description: flutter
      source: sdk
      version: "0.0.0"
    source_span:
      dependency: transitive
      description:
        name: source_span
        sha256: "56a02f1f4cd1a2d96303c0144c93bd6d909eea6bee6bf5a0e0b685edbd4c47ab"
        url: "https://pub.dev"
      source: hosted
      version: "1.10.2"
    stack_trace:
      dependency: transitive
      description:
        name: stack_trace
        sha256: "8b27215b45d22309b5cddda1aa2b19bdfec9df0e765f2de506401c071d38d1b1"
        url: "https://pub.dev"
      source: hosted
      version: "1.12.1"
    stream_channel:
      dependency: transitive
      description:
        name: stream_channel
        sha256: "969e04c80b8bcdf826f8f16579c7b14d780458bd97f56d107d3950fdbeef059d"
        url: "https://pub.dev"
      source: hosted
      version: "2.1.4"
    string_scanner:
      dependency: transitive
      description:
        name: string_scanner
        sha256: "921cd31725b72fe181906c6a94d987c78e3b98c2e205b397ea399d4054872b43"
        url: "https://pub.dev"
      source: hosted
      version: "1.4.1"
    term_glyph:
      dependency: transitive
      description:
        name: term_glyph
        sha256: "7f554798625ea768a7518313e58f83891c7f5024f88e46e7182a4558850a4b8e"
        url: "https://pub.dev"
      source: hosted
      version: "1.2.2"
    test_api:
      dependency: transitive
      description:
        name: test_api
        sha256: "93167629bfc610f71560ab9312acdda4959de4df6fac7492c89ff0d3886f6636"
        url: "https://pub.dev"
      source: hosted
      version: "0.7.9"
    vector_math:
      dependency: transitive
      description:
        name: vector_math
        sha256: d530bd74fea330e6e364cda7a85019c434070188383e1cd8d9777ee586914c5b
        url: "https://pub.dev"
      source: hosted
      version: "2.2.0"
    vm_service:
      dependency: transitive
      description:
        name: vm_service
        sha256: "45caa6c5917fa127b5dbcfbd1fa60b14e583afdc08bfc96dda38886ca252eb60"
        url: "https://pub.dev"
      source: hosted
      version: "15.0.2"
  sdks:
    dart: ">=3.11.0 <4.0.0"
    flutter: ">=3.35.0"

Steps to reproduce

Live demo: https://davidmigloz.github.io/flutter_selection_bug/ (dart2wasm release build)
Reproduction repo: https://github.com/davidmigloz/flutter_selection_bug

Steps

  1. Clone and run the reproduction app:

    git clone https://github.com/davidmigloz/flutter_selection_bug.git
    cd flutter_selection_bug
    flutter run -d chrome
  2. The app opens on /entities — a list screen with a table of entities. Verify text is selectable by dragging to select any email, name, or phone in the table.

  3. Click "View" on any entity to navigate to /entities/:entityId (the detail screen).

  4. On the detail screen, try to select "First Name: John" by clicking and dragging — it fails silently. The I-beam cursor appears, but drag-to-select does not initiate.

  5. Scroll down slightly — the dead zone shifts, making different rows unselectable.

  6. Hard-reload the browser on /entities/entity-1 directly (without navigating from the list) — text selection works perfectly.

Build mode behavior

Command Compiler Bug reproduces?
flutter run -d chrome DDC (debug) Yes
flutter run -d chrome --wasm dart2wasm (debug) Yes
flutter run -d chrome --release --wasm dart2wasm (release) Yes
flutter run -d chrome --release dart2js (release) No

The bug reproduces with DDC and dart2wasm but not dart2js.

Expected results

Text selection via drag-to-select should work on all visible text after navigating between routes within a ShellRoute, identical to how it works when the page is loaded directly (hard-reload).

Offstage pages kept mounted by the Navigator should not interfere with selection on the current page.

Actual results

After navigating from a parent route to a child route within a ShellRoute, invisible "dead zones" appear on the destination page where drag-to-select silently fails.

The dead zones correspond to the bounding boxes of selectable text from the previous (now offstage) page. The offstage page's Text widgets remain registered with the SelectionArea's SelectableRegion, and their bounding boxes overlap the current page's content, intercepting selection events.

  • No crash, no assertion error, no console warnings
  • The I-beam cursor still appears (misleadingly suggesting text is selectable)
  • The dead zone shifts when scrolling
  • Every page navigated to via ShellRoute is affected

Code sample

Full reproduction repo: https://github.com/davidmigloz/flutter_selection_bug

lib/main.dart
import 'package:flutter/material.dart';
import 'package:go_router/go_router.dart';

void main() {
  runApp(const MainApp());
}

final _router = GoRouter(
  initialLocation: '/entities',
  routes: [
    ShellRoute(
      builder: (context, state, child) => AppShell(child: child),
      routes: [
        GoRoute(
          path: '/entities',
          pageBuilder: (context, state) =>
              const NoTransitionPage(child: EntitiesListScreen()),
          routes: [
            GoRoute(
              path: ':entityId',
              pageBuilder: (context, state) => NoTransitionPage(
                child: EntityDetailScreen(
                  entityId: state.pathParameters['entityId']!,
                ),
              ),
            ),
          ],
        ),
      ],
    ),
  ],
);

class MainApp extends StatelessWidget {
  const MainApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp.router(
      title: 'SelectionArea Bug - go_router',
      theme: ThemeData(useMaterial3: true),
      routerConfig: _router,
    );
  }
}

/// Shell wraps all route content in a SelectionArea — this is the trigger.
class AppShell extends StatelessWidget {
  const AppShell({super.key, required this.child});
  final Widget child;

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: SelectionArea(child: child), // <-- Bug: offstage pages stay registered
    );
  }
}

class EntitiesListScreen extends StatelessWidget {
  const EntitiesListScreen({super.key});

  @override
  Widget build(BuildContext context) {
    return SingleChildScrollView(
      padding: const EdgeInsets.all(16),
      child: Column(
        crossAxisAlignment: CrossAxisAlignment.start,
        children: [
          const Text('Entities', style: TextStyle(fontSize: 24, fontWeight: FontWeight.bold)),
          const SizedBox(height: 16),
          Table(
            border: TableBorder.all(color: Colors.grey),
            children: [
              const TableRow(children: [
                Padding(padding: EdgeInsets.all(8), child: Text('Name', style: TextStyle(fontWeight: FontWeight.bold))),
                Padding(padding: EdgeInsets.all(8), child: Text('Email', style: TextStyle(fontWeight: FontWeight.bold))),
                Padding(padding: EdgeInsets.all(8), child: Text('Action', style: TextStyle(fontWeight: FontWeight.bold))),
              ]),
              for (final e in _entities)
                TableRow(children: [
                  Padding(padding: const EdgeInsets.all(8), child: Text(e.name)),
                  Padding(padding: const EdgeInsets.all(8), child: Text(e.email)),
                  Padding(
                    padding: const EdgeInsets.all(8),
                    child: TextButton(
                      onPressed: () => context.go('/entities/${e.id}'),
                      child: const Text('View'),
                    ),
                  ),
                ]),
            ],
          ),
        ],
      ),
    );
  }
}

class EntityDetailScreen extends StatelessWidget {
  const EntityDetailScreen({super.key, required this.entityId});
  final String entityId;

  @override
  Widget build(BuildContext context) {
    return SingleChildScrollView(
      padding: const EdgeInsets.all(16),
      child: Column(
        crossAxisAlignment: CrossAxisAlignment.start,
        children: [
          TextButton(onPressed: () => context.go('/entities'), child: const Text('← Back')),
          const SizedBox(height: 8),
          Text('Entity: $entityId', style: const TextStyle(fontSize: 24, fontWeight: FontWeight.bold)),
          const SizedBox(height: 16),
          // These rows fall in the "dead zone" matching the list page's table height
          for (final label in ['First Name: John', 'Last Name: Doe', 'Email: [email protected]', 'Phone: +31 6 1234 5678'])
            Padding(
              padding: const EdgeInsets.symmetric(vertical: 4),
              child: Text(label),
            ),
        ],
      ),
    );
  }
}

class _Entity {
  const _Entity(this.id, this.name, this.email);
  final String id, name, email;
}

const _entities = [
  _Entity('entity-1', 'John Doe', '[email protected]'),
  _Entity('entity-2', 'Jane Smith', '[email protected]'),
  _Entity('entity-3', 'Bob Johnson', '[email protected]'),
];
pubspec.yaml
name: flutter_selection_bug
description: "Minimal reproduction for SelectionArea + go_router dead zone bug"
publish_to: 'none'
version: 0.1.0+1

environment:
  sdk: ^3.11.0

dependencies:
  flutter:
    sdk: flutter
  go_router: ^17.1.0

dev_dependencies:
  flutter_test:
    sdk: flutter
  flutter_lints: ^6.0.0

flutter:
  uses-material-design: true

Screenshots or Videos

Screenshots / Video demonstration
Screen.Recording.2026-02-18.at.23.29.46.mov

Logs

Logs
Nothing relevant

Flutter Doctor output

Doctor output
[✓] Flutter (Channel stable, 3.41.1, on macOS 26.3 25D125 darwin-arm64, locale en-US)
    • Flutter version 3.41.1 on channel stable
    • Upstream repository https://github.com/flutter/flutter.git
    • Framework revision 582a0e7c55 (2026-02-12), 2026-02-12 17:12:32 -0800
    • Engine revision 3452d735bd
    • Dart version 3.11.0
    • DevTools version 2.54.1

[✓] Chrome - develop for the web
    • Chrome at /Applications/Google Chrome.app/Contents/MacOS/Google Chrome

[✓] Connected device (1 available)
    • Chrome (web) • chrome • web-javascript • Google Chrome 145.0.7632.76

[✓] Network resources
    • All expected network resources are available.

• No issues found!

Activity

  1. saurabh-mirajkar commented on Feb 19, 2026

    @saurabh-mirajkar
    Contributor

    @davidmigloz thanks for providing a detailed report.

  2. added
    platform-webWeb applications specifically
    and removed
    in triagePresently being triaged by the triage team
    on Feb 19, 2026
  3. added
    packageflutter/packages repository. See also p: labels.
    on Feb 23, 2026
  4. added
    P2Important issues not at the top of the work list
    on Feb 24, 2026
  5. moved this from Incoming Issues to In progress in SelectableRegion Improvementson Mar 2, 2026
  6. moved this from In progress to Incoming Issues in SelectableRegion Improvementson Mar 2, 2026
  7. moved this from Incoming Issues to Updated in SelectableRegion Improvementson Mar 5, 2026
  8. moved this from Updated to No status in SelectableRegion Improvementson Mar 5, 2026
  9. flutter-triage-bot commented on Jul 1, 2026

    @flutter-triage-bot

    This issue is assigned to @davidmigloz but has had no recent status updates. Please consider unassigning this issue if it is not going to be addressed in the near future. This allows people to have a clearer picture of what work is actually planned. Thanks!

  10. added
    ⏳Bot is counting down the days until it unassigns the issue
    on Jul 1, 2026
  11. davidmigloz commented on Jul 16, 2026

    @davidmigloz
    ContributorAuthor

    Quick status since the bot pinged.

    The crash side of this family (#151536) is covered by #184900, which I've just rebased and is ready for review again.

    The dead zones reported here are still unfixed though. The go_router fix (flutter/packages#11062) was closed in favor of a framework-level fix, but the direction we discussed there (wrapping non-current routes in SelectionContainer.disabled at the ModalRoute level) doesn't actually work: a nested SelectionArea installs its own registrar, which shadows the outer disabled scope, so the framework can't switch off a route's selectables from above.

    @Renzo-Olivares @chunhtai given that, what would you prefer? Reopening flutter/packages#11062 for the time being, until the a framework fix that makes selectable registration aware of layout/visibility inside SelectableRegion itself lands?

  12. removed
    ⏳Bot is counting down the days until it unassigns the issue
    on Aug 26, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

P2Important issues not at the top of the work listp: go_routerThe go_router packagepackageflutter/packages repository. See also p: labels.platform-webWeb applications specificallyteam-ecosystemOwned by Ecosystem teamtriaged-ecosystemTriaged by Ecosystem team

Type

No type

Projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions