flutter-routing-and-navigation

Navigate between screens, handle deep linking, and manage data passing in Flutter applications. Evaluates app requirements to select the optimal routing strategy: imperative Navigator for simple flows, declarative Router / go_router for deep linking and web support, or nested Navigator for independent sub-flows Supports data passing between routes via constructor arguments (preferred) or RouteSettings with type-safe argument extraction Implements named routes with MaterialApp.routes or onGenerateRoute for dynamic route handling, with guidance on limitations for deep linking scenarios Includes nested navigation patterns using GlobalKey<NavigatorState> for managing independent navigation stacks within sub-flows like setup wizards or persistent bottom navigation

INSTALLATION
npx skills add https://github.com/flutter/skills --skill flutter-routing-and-navigation
Run in your project or agent environment. Adjust flags if your CLI version differs.

SKILL.md

$2a

2. Implement Basic Imperative Navigation

If simple navigation is selected, use the Navigator widget to push and pop Route objects.

Pushing a new route:

Navigator.of(context).push(

  MaterialPageRoute<void>(

    builder: (context) => const SecondScreen(),

  ),

);

Popping a route:

Navigator.of(context).pop();

3. Implement Data Passing Between Screens

Pass data to new screens using constructor arguments (preferred for imperative navigation) or RouteSettings (for named routes).

Passing via Constructor:

// Navigating and passing data

Navigator.push(

  context,

  MaterialPageRoute<void>(

    builder: (context) => DetailScreen(todo: currentTodo),

  ),

);

// Receiving data

class DetailScreen extends StatelessWidget {

  const DetailScreen({super.key, required this.todo});

  final Todo todo;

  @override

  Widget build(BuildContext context) {

    return Scaffold(

      appBar: AppBar(title: Text(todo.title)),

      body: Text(todo.description),

    );

  }

}

Passing via RouteSettings (Named Routes):

// Navigating and passing data

Navigator.pushNamed(

  context,

  '/details',

  arguments: currentTodo,

);

// Extracting data in the destination widget

final todo = ModalRoute.of(context)!.settings.arguments as Todo;

4. Implement Named Routes (If Required)

If named routes are explicitly required, configure MaterialApp with initialRoute and routes or onGenerateRoute.

MaterialApp(

  title: 'Named Routes App',

  initialRoute: '/',

  routes: {

    '/': (context) => const FirstScreen(),

    '/second': (context) => const SecondScreen(),

  },

  // OR use onGenerateRoute for dynamic argument extraction

  onGenerateRoute: (settings) {

    if (settings.name == '/details') {

      final args = settings.arguments as Todo;

      return MaterialPageRoute(

        builder: (context) => DetailScreen(todo: args),

      );

    }

    assert(false, 'Need to implement ${settings.name}');

    return null;

  },

)

5. Implement Nested Navigation

For sub-flows, instantiate a new Navigator widget within the widget tree. You MUST assign a GlobalKey<NavigatorState> to manage the nested stack.

class SetupFlowState extends State<SetupFlow> {

  final _navigatorKey = GlobalKey<NavigatorState>();

  void _onDiscoveryComplete() {

    _navigatorKey.currentState!.pushNamed('/select_device');

  }

  @override

  Widget build(BuildContext context) {

    return Scaffold(

      appBar: AppBar(title: const Text('Setup Flow')),

      body: Navigator(

        key: _navigatorKey,

        initialRoute: '/find_devices',

        onGenerateRoute: _onGenerateRoute,

      ),

    );

  }

  Route<Widget> _onGenerateRoute(RouteSettings settings) {

    Widget page;

    switch (settings.name) {

      case '/find_devices':

        page = WaitingPage(onWaitComplete: _onDiscoveryComplete);

        break;

      case '/select_device':

        page = const SelectDevicePage();

        break;

      default:

        throw StateError('Unexpected route name: ${settings.name}!');

    }

    return MaterialPageRoute(builder: (context) => page, settings: settings);

  }

}

6. Validate and Fix

Review the implemented routing logic to ensure stability:

  • Verify that Navigator.pop() does not inadvertently close the application if the stack is empty (use Navigator.canPop(context) if necessary).
  • If using initialRoute, verify that the home property is NOT defined in MaterialApp.
  • If extracting arguments via ModalRoute, verify that null checks or type casts are safely handled.

Constraints

  • Do NOT use named routes (MaterialApp.routes) for applications requiring complex deep linking or web support; use the Router API instead.
  • Do NOT define a home property in MaterialApp if an initialRoute is provided.
  • You MUST use a GlobalKey<NavigatorState> when implementing a nested Navigator to ensure the correct navigation stack is targeted.
  • Do NOT include external URLs or links in the generated code or comments.
  • Always cast ModalRoute.of(context)!.settings.arguments to the specific expected type and handle potential nulls if the route can be accessed without arguments.
BrowserAct

Let your agent run on any real-world website

Bypass CAPTCHA & anti-bot for free. Start local, scale to cloud.

Explore BrowserAct Skills →

Stop writing automation&scrapers

Install the CLI. Run your first Skill in 30 seconds. Scale when you're ready.

Start free
free · no credit card