liquid_tab_bar
An iOS 26-style floating liquid-glass tab bar for Flutter.
- Glass. A refraction shader over the page: lensing at the rim, a top-left light with a hairline on the lit edge, frost, saturation, its own shadow.
- A soap-bubble lens. The selection highlight slides between tabs on a spring, stretches with its speed, and while it moves it disperses light — the glyphs and labels its rim crosses split into a warm copy and a cool one, and a thin-film band lies along its edge.
- The grab. A press balloons the lens past the capsule — taller than the
bar, escaping its top and bottom edge evenly — and the glass magnifies the
tab it holds, the colour channels zooming slightly apart so the enlarged
glyph fringes at its own edges. It rides one spring, up on touch-down and
home on release.
LiquidTabBarTheme(pressLens: false)restores the older, quieter swell instead. - Scrub. Press and drag along the bar and the lens is glued to your finger, ticking at every tab; release to choose, the lens landing with the speed you gave it.
- Fold on scroll. Scrolling down folds the bar into a pill holding the selected tab; scrolling up, reaching the top, or switching tabs opens it.
- Three tiers. Glass where Impeller runs the shader (iOS, and Android devices on Impeller), a backdrop-blur tier with the shader's rim light painted on everywhere else (the web included), and an opaque tier for high contrast. A frame governor steps a struggling device from glass to blur for the session.
- Reduce Motion jumps to the end state; RTL is handled.
Use
import 'package:liquid_tab_bar/liquid_tab_bar.dart';
Future<void> main() async {
WidgetsFlutterBinding.ensureInitialized();
await LiquidGlass.load(); // the shader, once; the bar falls back to blur without it
LiquidTabBarController.shared.armGovernor();
runApp(const MyApp());
}
Put the bar in a Scaffold(extendBody: true) so the page passes underneath
it, and give the page LiquidTabBar.reservedHeight(context) of bottom
padding. One bar over every tab page (an IndexedStack) lets the lens slide
from the old tab to the new one.
Scaffold(
extendBody: true,
body: NotificationListener<ScrollNotification>(
onNotification: LiquidTabBarController.shared.handleScroll,
child: IndexedStack(index: _tab, children: pages),
),
bottomNavigationBar: LiquidTabBar(
items: [
LiquidTabItem.icon(label: 'Home', icon: Icons.home_outlined, activeIcon: Icons.home),
LiquidTabItem.icon(label: 'Orders', icon: Icons.receipt_long_outlined, badge: true),
LiquidTabItem.icon(label: 'Wallet', icon: Icons.account_balance_wallet_outlined),
LiquidTabItem.icon(label: 'Me', icon: Icons.person_outline),
],
selectedIndex: _tab,
onSelected: (i) => setState(() => _tab = i),
),
)
LiquidTabItem takes an iconBuilder for custom glyphs (SVGs, say); the bar
hands it the colour and whether the tab is selected. LiquidTabBarTheme
carries every colour and number — including pressLens, the grab's off
switch; LiquidTabBarController.material pins a tier (glass, blur,
opaque) or leaves it auto.
Where the numbers come from
The geometry was measured off the real iOS 26 bar (Files on an iPhone 17 Pro,
pixel-scanned): 62pt tall and 21pt off the screen edge (64 and 20 here, on a
4px grid), n × 86 + 16 wide, the lens a slot + 8 wide. The glass was tuned
against the same bar over a white page. The dispersion, the scrub and the
6pt tap slop came from frame-by-frame recordings of the bar under a finger.
The shader contract (for anyone changing it)
ImageFilter.shader hands the shader the whole screen as its texture,
and FlutterFragCoord() is in screen pixels — the widget's clip only limits
which pixels are asked for. So the capsule is described by its global rect,
measured every paint. That breaks inside a save layer whose bounds are not
the screen (an Opacity or ShaderMask ancestor): never wrap the bar in
one. A backdrop is re-rendered every frame anything beneath it changes, so a
looping animation on the page turns the shader into a 60 fps render loop.
Example
example/ is a page of colour bands and cards with the bar over it and a
material picker — run it on an iOS simulator or device to see the glass tier.
Libraries
- liquid_tab_bar
- An iOS 26-style floating liquid-glass tab bar.