fluid_side_menu 1.1.0 copy "fluid_side_menu: ^1.1.0" to clipboard
fluid_side_menu: ^1.1.0 copied to clipboard

A premium, highly-customizable fluid side navigation menu with organic liquid-reveal transitions, staggered option entrance animations, and rich select feedback behaviors.

Fluid Side Menu #

Pub Version Pub Likes Platform License: BSD 3-Clause

A premium, highly-customizable fluid side navigation drawer for Flutter. Features an organic, gooey liquid-reveal transition using high-performance custom vector splines, staggered entrance animations, nested dropdown navigation, tactile haptic feedback, edge swipe gestures, and rich selection feedback behaviors.

Fluid Side Menu demo


Table of Contents #


Why Fluid Side Menu? #

While standard side drawers transition rigidly across the screen, Fluid Side Menu uses organic motion curves and wavy vector splines to deliver a fluid, high-fidelity navigational experience.

Key benefits include:

  • No Edge Pixelation: Custom waves are drawn dynamically as sharp vector paths, avoiding the pixelation or fuzzy edges common with raster masks.
  • Optimized Performance: Leverages isolated RepaintBoundary nodes and linear animation inputs to run smoothly at 60fps / 120fps even on lower-end devices.
  • Nested Navigation: Supports arbitrarily deep dropdown item trees with smooth animated expand/collapse transitions.
  • Custom Easing Curves: The fluid wave transition supports custom animation curves (springy elastic waves, snappy deceleration, or bounce reveals).
  • Scroll-Safe: The menu item list automatically scrolls when content overflows the screen — even with many expanded nested items.

Features #

  • Organic Liquid Transition: High-performance transition using custom vector wave splines that merge and expand across the screen.
  • Nested Dropdown Navigation: Items can declare child items (subItems) to create collapsible, animated dropdown groups of arbitrary depth.
  • Per-Item Sizing: Override text style and icon size on individual FluidMenuItem instances independent of global defaults.
  • Scrollable Item List: When the total item list overflows the screen, the menu scrolls automatically. Fully configurable via ScrollPhysics and ScrollController.
  • Staggered Option Animations: Smooth, delayed entrance animations for menu items (fade, scale, or springy slide-up).
  • Rich Selection Feedback: A collection of interactive tap animations including the Icon Slide Swap effect.
  • Tactile Haptic Feedback: Haptics on open, close, and item selection with de-duplicated triggers.
  • Edge Swipe Gestures: Pull-to-open from the left edge, swipe-to-close when the drawer is open.
  • Item Alignment: Align all menu items to the left, center, or right of the drawer.
  • Item-Level Customization: Override colors, text styles, spacings, and individual item sizes independently.
  • Programmatic Control: open(), close(), toggle() via FluidSideMenu.of(context) or a GlobalKey.

Getting started #

Add fluid_side_menu to your pubspec.yaml dependencies:

dependencies:
  fluid_side_menu: ^1.1.0

Then import the package in your Dart code:

import 'package:fluid_side_menu/fluid_side_menu.dart';

Usage #

Standard Setup #

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

void main() => runApp(const MyApp());

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Fluid Side Menu Demo',
      theme: ThemeData(useMaterial3: true),
      home: const DemoScreen(),
    );
  }
}

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

  @override
  State<DemoScreen> createState() => _DemoScreenState();
}

class _DemoScreenState extends State<DemoScreen> {
  @override
  Widget build(BuildContext context) {
    final List<FluidMenuItem> items = [
      FluidMenuItem(
        label: 'Home',
        page: const HomeScreen(),
        icon: const Icon(Icons.home),
      ),
      FluidMenuItem(
        label: 'About',
        page: const AboutScreen(),
        icon: const Icon(Icons.info),
      ),
      FluidMenuItem(
        label: 'Contact',
        page: const ContactScreen(),
        icon: const Icon(Icons.mail),
        // Item-level color overrides
        textColor: Colors.orangeAccent,
        iconColor: Colors.orangeAccent,
      ),
    ];

    return Scaffold(
      body: FluidSideMenu(
        fluidColor: Colors.black,
        duration: const Duration(milliseconds: 700),
        showBuiltInButtons: true,
        menuAnimationType: FluidMenuAnimationType.slide,
        selectAnimationType: FluidMenuSelectAnimationType.iconSlideSwap,
        menuItems: items,
      ),
    );
  }
}

Nested Dropdown Items #

Give any FluidMenuItem a subItems list to turn it into a collapsible dropdown group. Child items can themselves have subItems for arbitrary nesting depth. Parent items that only act as group headers do not need a page.

FluidMenuItem(
  label: 'Categories',
  icon: const Icon(Icons.category),
  // No page — this item is a dropdown header only
  subItems: [
    FluidMenuItem(
      label: 'Baskets',
      icon: const Icon(Icons.shopping_basket),
      subItems: [
        FluidMenuItem(
          label: 'Woven Baskets',
          page: const BasketsScreen(),
          icon: const Icon(Icons.shopping_bag),
        ),
        FluidMenuItem(
          label: 'Plastic Baskets',
          page: const BasketsScreen(),
          icon: const Icon(Icons.shopping_basket),
        ),
      ],
    ),
    FluidMenuItem(
      label: 'Gifts',
      page: const GiftsScreen(),
      icon: const Icon(Icons.card_giftcard),
    ),
  ],
),

Control the text and icon size for all child items via widget-level parameters:

FluidSideMenu(
  menuItems: items,
  subMenuItemTextStyle: TextStyle(fontSize: 20, fontWeight: FontWeight.w500),
  subMenuItemIconSize: 18.0,
  // ... other parameters
)

Per-Item Sizing #

Individual items can declare their own textStyle and iconSize, which take the highest priority — overriding the widget-level subMenuItemTextStyle/subMenuItemIconSize and the automatic depth-scaling factor.

FluidMenuItem(
  label: 'Featured Item',
  page: const FeaturedScreen(),
  icon: const Icon(Icons.star),
  textStyle: TextStyle(
    fontSize: 18,
    fontWeight: FontWeight.w700,
    letterSpacing: 0.3,
  ),
  iconSize: 22.0,
),

To disable automatic depth-based scaling entirely and rely only on explicit sizes, set scaleChildItemsBasedOnDepth: false on the FluidSideMenu widget.


Programmatic Control #

Open, close, or toggle the drawer from any descendant widget using the static accessor:

// Open the side menu
FluidSideMenu.of(context)?.open();

// Close the side menu
FluidSideMenu.of(context)?.close();

// Toggle the side menu
FluidSideMenu.of(context)?.toggle();

Alternatively assign a GlobalKey<FluidSideMenuState> and call key.currentState?.open().


Customizing the Reveal Background #

Pass a LinearGradient or RadialGradient to create a rich gradient appearance for the gooey wave:

FluidSideMenu(
  menuItems: items,
  fluidGradient: const LinearGradient(
    colors: [
      Color(0xFF0F0C20), // Dark indigo-black
      Color(0xFF15102A), // Dark violet
      Color(0xFF06040A), // Deep black
    ],
    begin: Alignment.topLeft,
    end: Alignment.bottomRight,
  ),
)

Scrollable Menu #

By default (enableScroll: true) the menu item list is wrapped in a SingleChildScrollView, allowing users to scroll down to reach items that overflow the screen height — especially useful when many dropdown groups are expanded simultaneously.

FluidSideMenu(
  menuItems: items,
  enableScroll: true,               // default — can omit
  scrollPhysics: const BouncingScrollPhysics(), // custom physics
  menuItemPadding: const EdgeInsets.symmetric(vertical: 9.0),
  subMenuItemPadding: const EdgeInsets.only(top: 10.0),
)

To disable scrolling entirely and keep a fixed layout, set enableScroll: false.


API Reference #

FluidSideMenu Options #

Parameter Type Default Description
menuItems List<FluidMenuItem> Required Navigation labels, icons, pages, and optional nested children.
child Widget? null Static main-screen override instead of routing through menu item pages.
contentBuilder Widget Function(BuildContext, Animation<double>)? null Fully custom content builder receiving the animation progress.
fluidColor Color Colors.black Background color of the reveal wave drawer.
fluidGradient Gradient? null Gradient override for the reveal wave background (supersedes fluidColor).
duration Duration 650 ms Length of the open and close wave transitions.
animationCurve Curve Curves.easeInOutCubic Easing curve applied to the fluid wave transition.
showBuiltInButtons bool true Auto-renders the top-left open button and top-right close toggle.
menuIcon Widget? null Custom widget for the open toggle button.
closeIcon Widget? null Custom widget for the close toggle button.
buttonRadius double 20.0 Corner radius of the circular open toggle button.
menuAnimationType FluidMenuAnimationType slide Entrance animation type for menu items (fade, scale, slide).
selectAnimationType FluidMenuSelectAnimationType scalePulse Tap selection feedback style. See Selection Feedback Animations.
menuItemTextStyle TextStyle? null Default text style for top-level menu item labels.
menuItemTextColor Color? null Default label color fallback for all items (if not set per-item).
menuItemIconColor Color? null Default icon color fallback for all items (if not set per-item).
menuItemSpacing double 12.0 Horizontal spacing between item icon and label.
menuItemPadding EdgeInsets? symmetric(vertical: 12) Vertical padding surrounding each top-level item row.
subMenuItemTextStyle TextStyle? null Widget-level text style applied to all nested child items.
subMenuItemIconSize double? null Widget-level icon size applied to all nested child items.
subMenuItemPadding EdgeInsets? only(top: 12) Vertical padding above each nested child item row.
scaleChildItemsBasedOnDepth bool true Whether child items are automatically scaled down per nesting level.
enableScroll bool true Wraps item list in a SingleChildScrollView when true.
scrollPhysics ScrollPhysics? ClampingScrollPhysics Scroll physics for the item list.
scrollController ScrollController? null External scroll controller for programmatic position control.
enableSwipeGestures bool true Whether swipe gestures can open or close the drawer.
edgeDragWidth double 30.0 Width of the left-edge drag zone when the drawer is closed.
revealOrigin Offset? null Custom origin point for the gooey reveal wave (defaults to menu button position).
enableHapticFeedback bool true Triggers haptic feedback at open, close, and item selection events.
itemAlignment FluidMenuItemAlignment center Horizontal alignment of menu items within the drawer (left, center, right).
onItemTapped ValueChanged<int>? null Callback triggered with the top-level item index when any item is selected.
onSubItemTapped void Function(int, int)? null Callback triggered with the parent index and child index when a nested item is selected.
menuHeader Widget? null Optional widget rendered at the top of the menu, above all items.
menuFooter Widget? null Optional widget rendered at the bottom of the menu, below all items.

FluidMenuItem Options #

Parameter Type Default Description
label String Required Label text displayed for the menu option.
page Widget? null Target screen widget shown when this item is selected. Required for leaf (non-parent) items.
icon Widget? null Prefix icon or widget displayed to the left of the label.
textColor Color? null Per-item label color override.
iconColor Color? null Per-item icon color override.
textStyle TextStyle? null Per-item text style override. Takes precedence over all widget-level styles and depth scaling.
iconSize double? null Per-item icon size override. Takes precedence over all widget-level sizes and depth scaling.
subItems List<FluidMenuItem>? null Nested child items. When provided, tapping the item expands or collapses a dropdown instead of navigating.
onTap VoidCallback? null Custom callback fired when this specific item is tapped, before any built-in expand or navigation logic.

Size resolution priority (highest to lowest):

  1. FluidMenuItem.textStyle / FluidMenuItem.iconSize (per-item)
  2. FluidSideMenu.subMenuItemTextStyle / FluidSideMenu.subMenuItemIconSize (widget-level)
  3. Automatic depth scaling (controlled by scaleChildItemsBasedOnDepth)

Selection Feedback Animations #

Value Behavior
iconSlideSwap Label fades and collapses; icon slides to the horizontal center. Other items dim to 0.25 opacity.
scalePulse Selected item scales up to 1.08. Other items dim to 0.35 opacity.
slideRight Selected item slides right. Other items dim to 0.35 opacity.
scaleDownOthers Selected item stays stable. Other items scale down to 0.9 and dim.
fadeOthers Selected item stays stable. Other items dim to 0.45 opacity.
none Immediate navigation without any feedback animation.

Item Alignment #

Value Behavior
FluidMenuItemAlignment.left Items are left-aligned with indentation increasing per nesting depth.
FluidMenuItemAlignment.center Items are centered in the drawer (default).
FluidMenuItemAlignment.right Items are right-aligned with indentation increasing per nesting depth.

Additional information #

Source Code and Contributions #

The source code and examples are hosted on GitHub. Contributions, bug reports, and feature requests are welcome via issues and pull requests.

Reporting Issues #

Please use the repository's GitHub Issues page to report bugs, request documentation updates, or propose new design features.

License #

This project is licensed under the BSD 3-Clause License — see the LICENSE file for details.

4
likes
160
points
81
downloads

Documentation

API reference

Publisher

verified publishermuditjpalvadi.tech

Weekly Downloads

A premium, highly-customizable fluid side navigation menu with organic liquid-reveal transitions, staggered option entrance animations, and rich select feedback behaviors.

Repository (GitHub)
View/report issues

License

BSD-3-Clause (license)

Dependencies

flutter

More

Packages that depend on fluid_side_menu