bottom_navigation_bar_kit 1.0.0 copy "bottom_navigation_bar_kit: ^1.0.0" to clipboard
bottom_navigation_bar_kit: ^1.0.0 copied to clipboard

A highly customizable Flutter bottom navigation bar package supporting 10 animation styles, light/dark mode, and Material 3 / Cupertino design systems.

bottom_navigation_bar_kit #

pub.dev GitHub Stars License: MIT

A highly customizable Flutter bottom navigation bar package featuring 10 premium animation styles, built-in light/dark mode, Material 3 & Cupertino presets, accessibility support, and zero external dependencies.


Support the Project ☕ #

If you find this library helpful and want to support its development, you can buy me a coffee!

Support Me on Ko-fi

Enjoying this library? Please consider giving it a ⭐ on GitHub to help it grow!


Visual Showcase #

Sliding Pill Underline Worm
Sliding Pill Underline Worm
Bubble Pop Top Bar Sweep
Bubble Pop Top Bar Sweep
Ink Drop Morphing Icon
Ink Drop Morphing Icon
Floating Dot Gradient Spotlight
Floating Dot Gradient Spotlight
Squeeze & Stretch Neon Pulse
Squeeze & Stretch Neon Pulse

Table of Contents #


Features #

  • 10 unique animation styles — all production-ready
  • Zero external dependencies — pure Flutter SDK
  • Light & Dark mode — automatic or manual
  • Material 3 & Cupertino preset themes
  • Badge support — text badges with custom colors
  • Accessibility — respects Reduce Motion system setting
  • Safe Area aware — correct bottom padding on all devices
  • Haptic feedback — subtle, tasteful touch feedback
  • 3–5 items — flexible item count
  • Customizable — colors, sizes, curves, durations, and more

Getting Started #

Add to your pubspec.yaml:

dependencies:
  bottom_navigation_bar_kit: ^1.0.0

Then run:

flutter pub get

Import the package:

import 'package:bottom_navigation_bar_kit/bottom_navigation_bar_kit.dart';

Quick Example #

import 'package:flutter/material.dart';
import 'package:bottom_navigation_bar_kit/bottom_navigation_bar_kit.dart';

class MyHomePage extends StatefulWidget {
  const MyHomePage({super.key});

  @override
  State<MyHomePage> createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  int _currentIndex = 0;

  final List<BottomNavItem> _items = const [
    BottomNavItem(
      icon: Icon(Icons.home_outlined),
      activeIcon: Icon(Icons.home),
      label: 'Home',
    ),
    BottomNavItem(
      icon: Icon(Icons.search_outlined),
      activeIcon: Icon(Icons.search),
      label: 'Search',
    ),
    BottomNavItem(
      icon: Icon(Icons.notifications_outlined),
      activeIcon: Icon(Icons.notifications),
      label: 'Alerts',
      badge: '3',
      badgeColor: Colors.redAccent,
    ),
    BottomNavItem(
      icon: Icon(Icons.person_outline),
      activeIcon: Icon(Icons.person),
      label: 'Profile',
    ),
  ];

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: const Center(child: Text('Content')),
      bottomNavigationBar: SlidingPillBottomNav(
        items: _items,
        currentIndex: _currentIndex,
        onTap: (i) => setState(() => _currentIndex = i),
      ),
    );
  }
}

All 10 Styles #


Style 1 — Sliding Pill #

A smooth pill-shaped background slides horizontally to the active tab.

Sliding Pill

SlidingPillBottomNav(
  items: _items,
  currentIndex: _currentIndex,
  onTap: (i) => setState(() => _currentIndex = i),
  // Optional customization:
  pillColor: Colors.blue.shade50,
  pillBorderRadius: BorderRadius.circular(24),
  activeIconColor: Colors.blue,
  inactiveIconColor: Colors.grey,
  theme: const NavTheme(
    height: 64,
    backgroundColor: Colors.white,
    activeColor: Colors.blue,
    inactiveColor: Colors.grey,
  ),
)

Parameters:

Parameter Type Default Description
items List<BottomNavItem> required Navigation items
currentIndex int required Active tab index
onTap ValueChanged<int> required Tap callback
pillColor Color? activeColor @ 15% Background color of the pill
pillBorderRadius BorderRadiusGeometry? circular(24) Corner radius of the pill
activeIconColor Color? theme.activeColor Icon color for active state
inactiveIconColor Color? theme.inactiveColor Icon color for inactive state
theme NavTheme NavTheme() Full theme override

Style 2 — Underline Worm #

An elastic underline bar stretches and snaps between tabs with a leading/trailing stagger for an organic "worm" feel. Includes a pill highlight and icon bounce on activation.

Underline Worm

UnderlineWormBottomNav(
  items: _items,
  currentIndex: _currentIndex,
  onTap: (i) => setState(() => _currentIndex = i),
  // Optional customization:
  wormColor: Colors.deepPurple,
  wormHeight: 3.0,
  wormBorderRadius: 8.0,
  elasticity: 0.35,
  showActivePill: true,
  pillHeight: 30.0,
  theme: NavTheme.light(),
)

Parameters:

Parameter Type Default Description
wormColor Color? theme.activeColor Color of the worm indicator
wormHeight double 3.0 Thickness of the worm bar
wormBorderRadius double 8.0 Corner radius of the worm bar
elasticity double 0.35 Stretch delay between edges (0.0–0.5)
showActivePill bool true Show pill highlight behind active icon
pillHeight double 30.0 Height of the active pill

Style 3 — Bubble Pop #

A circular soft-tinted bubble expands behind the active icon with a satisfying bounce animation. Fully self-contained with BubbleNavTheme.

Bubble Pop

BubblePopBottomNav(
  items: _items,
  currentIndex: _currentIndex,
  onTap: (i) => setState(() => _currentIndex = i),
  // Optional customization:
  bubbleSize: 42.0,
  showLabels: true,
  theme: BubbleNavTheme.light(seed: Colors.indigo),
)

With a dark theme:

BubblePopBottomNav(
  items: _items,
  currentIndex: _currentIndex,
  onTap: (i) => setState(() => _currentIndex = i),
  theme: BubbleNavTheme.dark(seed: Colors.tealAccent),
)

Parameters:

Parameter Type Default Description
bubbleSize double 42.0 Diameter of the bubble circle
showLabels bool true Show/hide text labels
theme BubbleNavTheme? BubbleNavTheme.light() Specialized theme (see BubbleNavTheme)

Note: BubblePopBottomNav uses its own BubbleNavTheme instead of NavTheme.


Style 4 — Top Bar Sweep #

A bold indicator bar at the very top edge of the nav sweeps with an elastic overshoot to the selected tab. Supports a full-height column tint and icon scale pop.

Top Bar Sweep

TopBarSweepBottomNav(
  items: _items,
  currentIndex: _currentIndex,
  onTap: (i) => setState(() => _currentIndex = i),
  // Optional customization:
  barColor: Colors.deepOrange,
  barHeight: 3.0,
  barWidthFactor: 0.55,
  overshootFactor: 0.6,
  showColumnTint: true,
  showTopDivider: true,
  theme: NavTheme.light(),
)

Parameters:

Parameter Type Default Description
barColor Color? theme.activeColor Color of the sweep bar
barHeight double 3.0 Thickness of the top indicator bar
barWidthFactor double 0.55 Width of bar as fraction of tab width (0.0–1.0)
overshootFactor double 0.6 ElasticOut tension (higher = more bounce)
showColumnTint bool true Subtle tint column behind active tab
showTopDivider bool true Hairline divider at top of nav bar

Style 5 — Ink Drop #

A radial ripple expands from the tapped icon and fades out, leaving a persistent ambient glow behind the active tab.

Ink Drop

InkDropBottomNav(
  items: _items,
  currentIndex: _currentIndex,
  onTap: (i) => setState(() => _currentIndex = i),
  // Optional customization:
  rippleColor: Colors.cyan,
  rippleOpacity: 0.22,
  rippleDuration: const Duration(milliseconds: 480),
  showAmbientGlow: true,
  rippleSizeFactor: 1.1,
  theme: NavTheme.dark(),
)

Parameters:

Parameter Type Default Description
rippleColor Color? theme.activeColor Color of the ripple and glow
rippleOpacity double 0.22 Peak opacity of the expanding ripple
rippleDuration Duration? 480ms Duration of ripple expand + fade
showAmbientGlow bool true Persistent soft glow behind active icon
rippleSizeFactor double 1.1 Ripple circle size relative to nav height

Style 6 — Morphing Icon #

Seamlessly crossfades between outline and filled icon variants. The icon IS the indicator — no external pill or bar. Features a dot indicator below the active tab.

Morphing Icon

MorphingIconBottomNav(
  items: _items,
  currentIndex: _currentIndex,
  onTap: (i) => setState(() => _currentIndex = i),
  // Optional customization:
  showDotIndicator: true,
  dotSize: 4.0,
  dotColor: Colors.blue,
  theme: NavTheme.light(),
)

Parameters:

Parameter Type Default Description
showDotIndicator bool true Small dot indicator below active icon
dotSize double 4.0 Diameter of the dot indicator
dotColor Color? theme.activeColor Color of the dot indicator

Style 7 — Floating Dot #

A dot arcs through the air in a parabolic trajectory from the previous tab to the newly selected one. The dot squishes and stretches at arc peak, and the icon bounces when the dot lands.

Floating Dot

FloatingDotBottomNav(
  items: _items,
  currentIndex: _currentIndex,
  onTap: (i) => setState(() => _currentIndex = i),
  // Optional customization:
  dotColor: Colors.amber,
  dotSize: 7.0,
  arcHeight: 18.0,
  showGlow: true,
  theme: NavTheme.light(),
)

Parameters:

Parameter Type Default Description
dotColor Color? theme.activeColor Color of the traveling dot
dotSize double 7.0 Base size of the dot at rest
arcHeight double 18.0 Height of the parabolic arc (px)
showGlow bool true Glow effect at arc peak

Style 8 — Gradient Spotlight #

A radial gradient spotlight shifts smoothly behind the active tab, creating a "lit from below" atmosphere. Built with a CustomPainter for smooth, GPU-efficient animation.

Gradient Spotlight

GradientSpotlightBottomNav(
  items: _items,
  currentIndex: _currentIndex,
  onTap: (i) => setState(() => _currentIndex = i),
  // Optional customization:
  gradientColors: [
    Colors.tealAccent.withOpacity(0.25),
    Colors.transparent,
  ],
  spotlightRadius: 0.55,
  showEcho: true,
  theme: NavTheme.dark(),
)

Parameters:

Parameter Type Default Description
gradientColors List<Color>? [activeColor @ 22%, transparent] Two gradient colors: center/bright → edge/transparent
spotlightRadius double 0.55 Radius as a fraction of nav width (0.0–1.5)
showEcho bool true Dimmer spotlight echo for depth

Style 9 — Squeeze & Stretch #

A bottom indicator bar dynamically squeezes narrow then stretches wide when a new tab is selected, with an elastic curve for a satisfying micro-interaction.

Squeeze & Stretch

SqueezeStretchBottomNav(
  items: _items,
  currentIndex: _currentIndex,
  onTap: (i) => setState(() => _currentIndex = i),
  // Optional customization:
  indicatorColor: Colors.green,
  squeezeWidth: 20.0,
  stretchWidth: 60.0,
  indicatorHeight: 3.0,
  animationCurve: Curves.easeInOutBack,
  theme: NavTheme.light(),
)

Parameters:

Parameter Type Default Description
indicatorColor Color? theme.activeColor Color of the indicator bar
squeezeWidth double 20.0 Width at the squeeze (narrow) phase
stretchWidth double 60.0 Width at the stretch (wide) phase
indicatorHeight double 3.0 Height of the indicator
animationCurve Curve? easeInOutBack Curve controlling the animation shape

Style 10 — Neon Pulse #

A pulsing neon glow effect radiates behind the active tab icon. Each tab gets its own neon color. Best used with dark backgrounds.

Neon Pulse

NeonPulseBottomNav(
  items: _items,
  currentIndex: _currentIndex,
  onTap: (i) => setState(() => _currentIndex = i),
  neonColors: const [
    Colors.cyanAccent,
    Colors.purpleAccent,
    Colors.pinkAccent,
    Colors.greenAccent,
  ],
  pulseSpeed: const Duration(milliseconds: 800),
  glowSpread: 12.0,
  backgroundColor: const Color(0xFF0D0D0D),
  theme: NavTheme.dark(),
)

Parameters:

Parameter Type Default Description
neonColors List<Color>? theme.activeColor Per-tab neon colors (cycles if fewer than items)
pulseSpeed Duration 800ms Speed of the pulsing glow animation
glowSpread double 12.0 Base spread radius of the glow
backgroundColor Color Color(0xFF0D0D0D) Nav bar background (recommend dark)

Core API #

BottomNavItem #

Represents a single navigation tab item.

const BottomNavItem({
  required Widget icon,        // Inactive icon widget
  required Widget activeIcon,  // Active (filled) icon widget
  required String label,       // Text label
  String? badge,               // Badge text (e.g. "3", "NEW")
  Color? badgeColor,           // Badge background color
})

Example:

const BottomNavItem(
  icon: Icon(Icons.home_outlined),
  activeIcon: Icon(Icons.home),
  label: 'Home',
  badge: '5',
  badgeColor: Colors.redAccent,
)

The primary theme class used by all styles except BubblePopBottomNav.

const NavTheme({
  Color backgroundColor,      // Bar background color
  Color activeColor,          // Active icon/indicator color
  Color inactiveColor,        // Inactive icon/label color
  TextStyle labelStyle,       // Base label style
  TextStyle? activeLabelStyle, // Active label style override
  double height,              // Bar height in logical pixels
  EdgeInsets padding,         // Internal padding
  double iconSize,            // Icon size
  Duration animationDuration, // Animation duration
  Curve animationCurve,       // Animation curve
})

Factory presets:

// Light mode
NavTheme.light(backgroundColor, activeColor, inactiveColor)

// Dark mode
NavTheme.dark(backgroundColor, activeColor, inactiveColor, height, iconSize, animationDuration)

// Material 3
NavTheme.material3()

// iOS/Cupertino
NavTheme.cupertino()

Defaults table:

Property Default
backgroundColor Colors.white
activeColor Colors.blue
inactiveColor Colors.grey
height 64.0
iconSize 24.0
animationDuration 300ms
animationCurve Curves.easeInOut
labelStyle TextStyle(fontSize: 12)
padding EdgeInsets.symmetric(horizontal: 8, vertical: 8)

BubbleNavTheme #

A specialized theme for BubblePopBottomNav with additional bubble-specific properties.

const BubbleNavTheme({
  required Color backgroundColor,
  required Color activeColor,
  required Color inactiveColor,
  required Color bubbleColor,   // Tint color of the bubble circle
  double height,                // Bar height (default: 72.0)
  double iconSize,              // Icon size (default: 24.0)
  TextStyle labelStyle,         // Label text style
  Duration animationDuration,   // Animation duration (default: 320ms)
  BorderRadius? containerRadius, // Corner radius of the nav bar container
  List<BoxShadow>? shadows,     // Shadow(s) on the nav bar container
})

Factory presets:

// Light with optional seed color
BubbleNavTheme.light(Color? seed)

// Dark with optional seed color
BubbleNavTheme.dark(Color? seed)

Example with full customization:

BubblePopBottomNav(
  items: _items,
  currentIndex: _currentIndex,
  onTap: (i) => setState(() => _currentIndex = i),
  theme: BubbleNavTheme(
    backgroundColor: Colors.white,
    activeColor: Colors.indigo,
    inactiveColor: Colors.grey.shade400,
    bubbleColor: Colors.indigo.withOpacity(0.12),
    height: 72,
    containerRadius: BorderRadius.circular(20),
    shadows: [
      BoxShadow(
        color: Colors.black12,
        blurRadius: 20,
        offset: Offset(0, -4),
      ),
    ],
  ),
)

Theming & Customization #

Dark Mode #

All styles support dark mode either automatically (via Theme.of(context).brightness) or manually:

// Manual dark theme for any style
SlidingPillBottomNav(
  items: _items,
  currentIndex: _currentIndex,
  onTap: (i) => setState(() => _currentIndex = i),
  theme: NavTheme.dark(
    activeColor: Colors.tealAccent,
  ),
)

// Bubble Pop auto-detects dark mode via Theme
BubblePopBottomNav(
  items: _items,
  currentIndex: _currentIndex,
  onTap: (i) => setState(() => _currentIndex = i),
  // No theme needed — auto-detects from Theme.of(context).brightness
)

Custom Animation Speed #

SlidingPillBottomNav(
  items: _items,
  currentIndex: _currentIndex,
  onTap: (i) => setState(() => _currentIndex = i),
  theme: const NavTheme(
    animationDuration: Duration(milliseconds: 500),
    animationCurve: Curves.elasticOut,
  ),
)

Integrate with PageView #

class _MyState extends State<MyPage> {
  int _currentIndex = 0;
  late PageController _pageController;

  @override
  void initState() {
    super.initState();
    _pageController = PageController();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: PageView(
        controller: _pageController,
        onPageChanged: (i) => setState(() => _currentIndex = i),
        children: const [/* pages */],
      ),
      bottomNavigationBar: SlidingPillBottomNav(
        items: _items,
        currentIndex: _currentIndex,
        onTap: (i) {
          setState(() => _currentIndex = i);
          _pageController.jumpToPage(i);
        },
      ),
    );
  }
}

Accessibility #

The kit fully respects the system's Reduce Motion accessibility setting:

  • All animations are skipped (instant snap) when the user has enabled "Reduce Motion" in system settings.
  • This is handled automatically in every style via the BaseBottomNavStateMixin.reduceMotion getter — no additional setup required.
  • Badge text is rendered as plain Text widgets, compatible with screen readers.

License #

This project is licensed under the MIT License - see the LICENSE file for details.

1
likes
160
points
76
downloads

Documentation

API reference

Publisher

verified publisherdimassfeb.com

Weekly Downloads

A highly customizable Flutter bottom navigation bar package supporting 10 animation styles, light/dark mode, and Material 3 / Cupertino design systems.

Repository (GitHub)
View/report issues

License

MIT (license)

Dependencies

flutter

More

Packages that depend on bottom_navigation_bar_kit