Skip to content

Navigator Basics

In React you call useNavigate() to get a navigate function, then call navigate('/detail') to change the current route. Flutter’s equivalent is Navigator.push(context, route) — but instead of a URL string, you pass a Route object that knows how to build the next screen. The key difference is that Flutter maintains a real widget stack: the previous screen stays alive in memory below the new one, just as browser history keeps previous pages alive in the tab’s session.

The Android back button and iOS swipe-back gesture are handled automatically by the Navigator — you do not need to wire up a back handler unless you want to intercept it.

React
// React — navigate programmatically
import { useNavigate } from 'react-router-dom';
function HomeScreen() {
const navigate = useNavigate();
return (
<button onClick={() => navigate('/detail')}>
Go to Detail
</button>
);
}
// Go back
function DetailScreen() {
const navigate = useNavigate();
return (
<button onClick={() => navigate(-1)}>
Back
</button>
);
}
Flutter
// Flutter — push / pop
class HomeScreen extends StatelessWidget {
const HomeScreen({super.key});
@override
Widget build(BuildContext context) {
return ElevatedButton(
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => const DetailScreen(),
),
);
},
child: const Text('Go to Detail'),
);
}
}
// Go back
class DetailScreen extends StatelessWidget {
const DetailScreen({super.key});
@override
Widget build(BuildContext context) {
return ElevatedButton(
onPressed: () => Navigator.pop(context),
child: const Text('Back'),
);
}
}
import 'package:flutter/material.dart';

void main() => runApp(const MyApp());

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

  @override
  Widget build(BuildContext context) {
    return const MaterialApp(
      home: HomeScreen(),
    );
  }
}

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

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('Home')),
      body: Center(
        child: Column(
          mainAxisSize: MainAxisSize.min,
          children: [
            const Text(
              'You are on the Home screen.',
              style: TextStyle(fontSize: 16),
            ),
            const SizedBox(height: 24),
            ElevatedButton(
              onPressed: () {
                Navigator.push(
                  context,
                  MaterialPageRoute(
                    builder: (context) => const DetailScreen(),
                  ),
                );
              },
              child: const Text('Go to Detail'),
            ),
          ],
        ),
      ),
    );
  }
}

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

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('Detail')),
      body: Center(
        child: Column(
          mainAxisSize: MainAxisSize.min,
          children: [
            const Text(
              'You are on the Detail screen.',
              style: TextStyle(fontSize: 16),
            ),
            const SizedBox(height: 24),
            ElevatedButton(
              onPressed: () => Navigator.pop(context),
              child: const Text('Go Back'),
            ),
          ],
        ),
      ),
    );
  }
}
What does Navigator.push add to the Flutter navigation stack?
Why does Navigator.push require a BuildContext?
What is MaterialPageRoute responsible for?
How does Flutter handle the Android back button without any extra code?