liquid_glass_bottom_nav 0.0.9
liquid_glass_bottom_nav: ^0.0.9 copied to clipboard
A beautiful, liquid frosted-glass floating bottom navigation bar for Flutter.
liquid_glass_bottom_nav #
A floating frosted-glass pill bottom navigation bar for Flutter. Features a physics-based sliding bubble indicator, drag-to-switch gestures, and a squash-and-stretch tilt animation. Built on top of liquid_glass_renderer — embedded directly, so no extra dependency is needed.
Automatically falls back to a standard Material bottom nav on devices that don't support Impeller (Skia, web, Windows, Linux).

Installation #
dependencies:
liquid_glass_bottom_nav: ^0.0.7
Quick start #
Wrap your Scaffold body in a Stack and place LiquidGlassNavBar as a Positioned overlay at the bottom. Add LiquidGlassNavBar.contentBottomInset as bottom padding on any scrollable content so it clears the nav bar.
import 'package:liquid_glass_bottom_nav/liquid_glass_bottom_nav.dart';
class MyApp extends StatefulWidget {
@override
State<MyApp> createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
int _selectedIndex = 0;
final _items = const [
LiquidGlassNavItem(id: 'home', icon: Icons.home_rounded, label: 'Home'),
LiquidGlassNavItem(id: 'search', icon: Icons.search_rounded, label: 'Search'),
LiquidGlassNavItem(id: 'profile', icon: Icons.person_rounded, label: 'Profile'),
];
@override
Widget build(BuildContext context) {
return Scaffold(
body: Stack(
children: [
// Your page content — add bottom padding so it clears the nav bar
Positioned.fill(
child: SingleChildScrollView(
padding: const EdgeInsets.only(
bottom: LiquidGlassNavBar.contentBottomInset,
),
child: /* your content */,
),
),
// The nav bar
LiquidGlassNavBar(
items: _items,
selectedIndex: _selectedIndex,
onTap: (index) => setState(() => _selectedIndex = index),
),
],
),
);
}
}
Customization #
Colors #
LiquidGlassNavBar(
items: _items,
selectedIndex: _selectedIndex,
onTap: (i) => setState(() => _selectedIndex = i),
activeColor: const Color(0xFF4CAF50), // active icon + label
inactiveColor: Colors.white60, // inactive icon + label
),
Icon size and label style #
LiquidGlassNavBar(
items: _items,
selectedIndex: _selectedIndex,
onTap: (i) => setState(() => _selectedIndex = i),
iconSize: 24,
labelStyle: const TextStyle(
fontSize: 11,
fontWeight: FontWeight.w600,
letterSpacing: 0.3,
),
),
Custom icon widget #
Use iconWidget when you need an SVG, asset image, or any custom painter instead of a IconData. The widget is wrapped in IconTheme so any widget that respects it (including SvgPicture.asset with colorFilter: ColorFilter.mode(iconTheme.color!, BlendMode.srcIn)) will automatically receive the active/inactive color.
LiquidGlassNavItem(
id: 'mosque',
label: 'Prayer',
iconWidget: SvgPicture.asset(
'assets/icons/mosque.svg',
colorFilter: ColorFilter.mode(
IconTheme.of(context).color ?? Colors.white,
BlendMode.srcIn,
),
),
),
Insets #
LiquidGlassNavBar(
items: _items,
selectedIndex: _selectedIndex,
onTap: (i) => setState(() => _selectedIndex = i),
insets: 12.0, // horizontal margin from screen edge + bottom margin above safe area
),
API reference #
LiquidGlassNavBar #
| Parameter | Type | Default | Description |
|---|---|---|---|
items |
List<LiquidGlassNavItem> |
required | Navigation items |
selectedIndex |
int |
required | Index of the active tab |
onTap |
ValueChanged<int> |
required | Called when a tab is tapped or dragged to |
activeColor |
Color? |
colorScheme.primary |
Icon and label color for the active tab |
inactiveColor |
Color? |
colorScheme.onSurface |
Icon and label color for inactive tabs |
iconSize |
double |
22 |
Size of the icon in each tab |
labelStyle |
TextStyle? |
bodySmall + w500 |
Merged over the default label style. Color is always driven by active/inactive color. |
insets |
double |
16 |
Horizontal margin from screen edge and bottom margin above the system safe area |
impellerSupported |
bool |
true |
Pass false to force the legacy Material fallback (useful when Impeller is unavailable) |
LiquidGlassNavItem #
| Parameter | Type | Required | Description |
|---|---|---|---|
id |
String |
yes | Unique identifier for this item |
label |
String |
yes | Tab label text |
icon |
IconData? |
one of icon/iconWidget |
Material or Cupertino icon |
iconWidget |
Widget? |
one of icon/iconWidget |
Custom icon widget — takes priority over icon. Wrapped in IconTheme. |
Static constants #
| Constant | Value | Description |
|---|---|---|
LiquidGlassNavBar.contentBottomInset |
96.0 |
Bottom padding to add to scrollable content so it clears the floating nav bar |
LiquidGlassBackButton #
A floating glass back button that matches the nav bar's visual language. Place it as a top-left overlay inside a Stack.
Stack(
children: [
YourPageContent(),
Positioned(
top: MediaQuery.of(context).padding.top + 12,
left: 16,
child: LiquidGlassBackButton(
onTap: () => Navigator.of(context).pop(),
),
),
],
)
LiquidGlassBackButton #
| Parameter | Type | Default | Description |
|---|---|---|---|
onTap |
VoidCallback? |
Navigator.maybePop |
Tap handler. Defaults to popping the current route. |
color |
Color? |
colorScheme.onSurface |
Chevron icon color |
size |
double |
44 |
Width and height of the glass pill |
borderRadius |
double |
14 |
Corner radius of the glass shape |
impellerSupported |
bool |
true |
Pass false to fall back to a plain IconButton |
Impeller note #
The glass effect requires Flutter's Impeller renderer.
- iOS — Impeller is on by default. No action needed.
- Android — Impeller must be enabled in
AndroidManifest.xml:
<meta-data
android:name="io.flutter.embedding.android.EnableImpeller"
android:value="true" />
When Impeller is unavailable (older Android, web, desktop), the widget automatically renders a standard Material bottom navigation bar. You can also force the fallback by passing impellerSupported: false.
License #
MIT