Route-Aware Components
Some components are not limited to the current screen — they may navigate to new routes to show additional functionality.
Example:
- An Audio component not only plays a track but also lets the user open a playlist screen with more details.
- A Chat component may show a chat preview inside a feed, and then open a full chat screen when tapped.
Key Design Decisions
- Use go_router
- All navigation must use
go_router, since our applications follow a declarative routing pattern.
- All navigation must use
- Expose Route List
- Components should expose a list of routes (
GoRoute) that can be added to the app’s main router. - This ensures routes are defined upfront (as required by go_router).
- Components should expose a list of routes (
- Theming
- Theming must be passed inherited way (using
Theme.of(context)or customInheritedWidget), so sub-routes look consistent with the rest of the app.
- Theming must be passed inherited way (using
Example: Audio Component with Playlist Route
Audio Component (Clickable → Navigates to Playlist)
class AudioComponent extends StatelessWidget {
final String playlistId;
const AudioComponent({super.key, required this.playlistId});
@override
Widget build(BuildContext context) {
return ListTile(
leading: const Icon(Icons.music_note),
title: Text("Playlist $playlistId"),
onTap: () {
// Declarative navigation
context.go('/playlist/$playlistId');
},
);
}
/// Routes exposed by this component
static List<GoRoute> routes = [
GoRoute(
path: '/playlist/:id',
builder: (context, state) {
final id = state.pathParameters['id']!;
return PlaylistScreen(playlistId: id);
},
),
];
}Playlist Screen (Standalone UI)
class PlaylistScreen extends StatelessWidget {
final String playlistId;
const PlaylistScreen({super.key, required this.playlistId});
@override
Widget build(BuildContext context) {
final theme = Theme.of(context); // Inherited theme still applies
return Scaffold(
appBar: AppBar(title: Text("Playlist $playlistId")),
body: Center(
child: Text(
"Songs for playlist $playlistId",
style: theme.textTheme.bodyLarge,
),
),
);
}
}Application Router (Using Component Routes)
final GoRouter router = GoRouter(
routes: [
GoRoute(
path: '/',
builder: (context, state) => const HomeScreen(),
),
// Inject component routes here
...AudioComponent.routes,
],
);Home Screen Example
class HomeScreen extends StatelessWidget {
const HomeScreen({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text("Home")),
body: ListView(
children: const [
AudioComponent(playlistId: "101"),
AudioComponent(playlistId: "202"),
],
),
);
}
}