Tapping the tab you're already on should scroll that page to the top. Both Apple's HIG and Material spec it, so users reach for it without thinking. Tap it again when at the top and many apps do a second thing, like focusing search:
Flutter's BottomNavigationBar doesn't do any of it for you. Make it yourself.
Create and store ScrollControllers and FocusNodes for each tab. When the user taps the tab they're already on, scroll it to the top. If it's already at the top, focus the text field on that page if it has one:
import 'package:flutter/material.dart';class BottomNavigationReselect { BottomNavigationReselect._(); static final ScrollController homeScrollController = ScrollController(); static final ScrollController catalogScrollController = ScrollController(); static final ScrollController cartScrollController = ScrollController(); static final ScrollController favoritesScrollController = ScrollController(); static final ScrollController accountScrollController = ScrollController(); static final FocusNode homeSearchFocusNode = FocusNode(); static void scrollToTopOrFocusSearch(int index) { // scroll to top final ScrollController scroller = switch (index) { 0 => homeScrollController, 1 => catalogScrollController, 2 => cartScrollController, 3 => favoritesScrollController, _ => accountScrollController, }; final bool atTop = !scroller.hasClients || scroller.offset <= 0; if (!atTop) { scroller.animateTo( 0, duration: const Duration(milliseconds: 300), curve: Curves.easeOutCubic, ); return; } // already at top, focus search final FocusNode? searchFocus = switch (index) { 0 => homeSearchFocusNode, _ => null, }; searchFocus?.requestFocus(); }}
Wire it in onTap. When the tapped index equals the current one, run the action:
This is a simple example. Keep the controllers wherever fits your app, put them in a map, key them with an enum instead of an int etc. The shape is yours; only the idea matters: detect the reselect, then scroll to top or focus a search field.
A note on lifecycle. These controllers and focus nodes live as long as the app, because the bottom nav is always on screen. If you want to, add a dispose and call from root widget that holds the bottom nav. Never dispose them while in use.