Menu Kit

Animated dropdown and fan menus for Flutter with ready-to-use directional and radial presets.

Menu Kit gives you small, composable menu widgets that work with any trigger and any child widgets. Use it for floating action menus, tool palettes, context actions, quick navigation, and radial command menus.

Features

  • DropDownMenu for linear left, right, up, down, and bidirectional layouts.
  • FanMenu for circular and half-curve radial layouts.
  • Custom trigger builder with a simple toggleMenu callback.
  • Works with any Flutter widget as a menu item.
  • Configurable offset, childrenMargin, triggerMargin, and radius.
  • Lightweight FlowDelegate animations with no platform-specific code.

Installation

Add Menu Kit to your pubspec.yaml:

dependencies:
  menu_kit: ^1.0.0

Then fetch packages:

flutter pub get

Import

import 'package:menu_kit/menu_kit.dart';

Quick Start

Create and dispose an AnimationController, then pass it to a menu widget.

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

  @override
  State<QuickMenu> createState() => _QuickMenuState();
}

class _QuickMenuState extends State<QuickMenu>
    with SingleTickerProviderStateMixin {
  late final AnimationController controller;

  @override
  void initState() {
    super.initState();
    controller = AnimationController(
      vsync: this,
      duration: const Duration(milliseconds: 350),
    );
  }

  @override
  void dispose() {
    controller.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return DropDownMenu(
      controller: controller,
      preset: MenuPreset.centerOpeningDown,
      trigger: (toggleMenu) => FloatingActionButton(
        onPressed: toggleMenu,
        child: const Icon(Icons.add),
      ),
      children: const [
        FloatingActionButton.small(
          heroTag: 'home',
          onPressed: null,
          child: Icon(Icons.home),
        ),
        FloatingActionButton.small(
          heroTag: 'favorite',
          onPressed: null,
          child: Icon(Icons.favorite),
        ),
      ],
    );
  }
}

Examples

Run the included example app:

cd example
flutter run

The example shows every dropdown and fan preset in grouped tabs, including custom spacing and offset controls.

Use DropDownMenu when actions should spread along a straight line.

DropDownMenu(
  controller: controller,
  preset: MenuPreset.centerOpeningRight,
  offset: Offset.zero,
  childrenMargin: const EdgeInsets.all(6),
  trigger: (toggleMenu) => IconButton.filled(
    onPressed: toggleMenu,
    icon: const Icon(Icons.add),
  ),
  children: menuActions,
)

MenuPreset includes center, edge, corner, and bidirectional layouts:

centerOpeningLeft, centerOpeningRight, centerOpeningUp, centerOpeningDown, leftCenterOpeningRight, leftCenterOpeningUp, leftCenterOpeningDown, rightCenterOpeningLeft, rightCenterOpeningUp, rightCenterOpeningDown, topCenterOpeningLeft, topCenterOpeningRight, topCenterOpeningDown, bottomCenterOpeningLeft, bottomCenterOpeningRight, bottomCenterOpeningUp, topLeftOpeningRight, topLeftOpeningDown, topRightOpeningLeft, topRightOpeningDown, bottomLeftOpeningRight, bottomLeftOpeningUp, bottomRightOpeningLeft, bottomRightOpeningUp, centerOpeningLR, centerOpeningTD, leftCenterOpeningTD, rightCenterOpeningTD, topCenterOpeningLR, and bottomCenterOpeningLR.

Demo Description
Center Opening (Down)

DropDownMenu(preset: MenuPreset.centerOpeningDown, offset: Offset.zero, controller: controller, trigger: (toggleMenu) => FloatingActionButton(onPressed: toggleMenu, child: const Icon(Icons.add)), children: menuActions)
Demo Description
Center Opening (Left)

DropDownMenu(preset: MenuPreset.centerOpeningLeft, offset: Offset.zero, controller: controller, trigger: (toggleMenu) => FloatingActionButton(onPressed: toggleMenu, child: const Icon(Icons.add)), children: menuActions)
Demo Description
Center Opening (Right)

DropDownMenu(preset: MenuPreset.centerOpeningRight, offset: Offset.zero, controller: controller, trigger: (toggleMenu) => FloatingActionButton(onPressed: toggleMenu, child: const Icon(Icons.add)), children: menuActions)
Demo Description
Center Opening (Up)

DropDownMenu(preset: MenuPreset.centerOpeningUp, offset: Offset.zero, controller: controller, trigger: (toggleMenu) => FloatingActionButton(onPressed: toggleMenu, child: const Icon(Icons.add)), children: menuActions)
Demo Description
Center Opening (Left and Right)

DropDownMenu(preset: MenuPreset.centerOpeningLR, offset: Offset.zero, controller: controller, trigger: (toggleMenu) => FloatingActionButton(onPressed: toggleMenu, child: const Icon(Icons.add)), children: menuActions)
Demo Description
Center Opening (Top and Down)

DropDownMenu(preset: MenuPreset.centerOpeningTD, offset: Offset.zero, controller: controller, trigger: (toggleMenu) => FloatingActionButton(onPressed: toggleMenu, child: const Icon(Icons.add)), children: menuActions)

Fan Menu

Use FanMenu when actions should spread around the trigger in an arc.

FanMenu(
  controller: controller,
  preset: FanMenuPreset.circular,
  radius: 24,
  trigger: (toggleMenu) => FloatingActionButton(
    onPressed: toggleMenu,
    child: const Icon(Icons.add),
  ),
  children: menuActions,
)

Fan Presets

FanMenuPreset includes circular, leftHalfCurve, rightHalfCurve, topHalfCurve, bottomHalfCurve, centerTopHalf, centerBottomHalf, centerLeftHalf, and centerRightHalf.

Demo Description
Circular Fan Menu

FanMenu(preset: FanMenuPreset.circular, offset: Offset.zero, controller: controller, trigger: (toggleMenu) => FloatingActionButton(onPressed: toggleMenu, child: const Icon(Icons.add)), children: menuActions)
Demo Description
Center Top Half Fan Menu

FanMenu(radius: 20, preset: FanMenuPreset.centerTopHalf, offset: Offset.zero, controller: controller, trigger: (toggleMenu) => FloatingActionButton(onPressed: toggleMenu, child: const Icon(Icons.add)), children: menuActions)
Demo Description
Center Bottom Half Fan Menu

FanMenu(radius: 20, preset: FanMenuPreset.centerBottomHalf, offset: Offset.zero, controller: controller, trigger: (toggleMenu) => FloatingActionButton(onPressed: toggleMenu, child: const Icon(Icons.add)), children: menuActions)
Demo Description
Center Left Half Fan Menu

FanMenu(radius: 20, preset: FanMenuPreset.centerLeftHalf, offset: Offset.zero, controller: controller, trigger: (toggleMenu) => FloatingActionButton(onPressed: toggleMenu, child: const Icon(Icons.add)), children: menuActions)
Demo Description
Center Right Half Fan Menu

FanMenu(radius: 20, preset: FanMenuPreset.centerRightHalf, offset: Offset.zero, controller: controller, trigger: (toggleMenu) => FloatingActionButton(onPressed: toggleMenu, child: const Icon(Icons.add)), children: menuActions)
Demo Description
Customize Item Spacing with radius

FanMenu(radius: 30, preset: FanMenuPreset.centerLeftHalf, offset: Offset.zero, controller: controller, trigger: (toggleMenu) => FloatingActionButton(onPressed: toggleMenu, child: const Icon(Icons.add)), children: menuActions)

Smaller radius values keep items closer. Larger values increase distance from the trigger.

Customization

Use offset to move the whole menu after the preset alignment is calculated:

Demo Description
Custom Menu Position Using offset

DropDownMenu(preset: MenuPreset.centerOpeningDown, offset: const Offset(70, -150), controller: controller, trigger: (toggleMenu) => FloatingActionButton(onPressed: toggleMenu, child: const Icon(Icons.add)), children: menuActions)

Positive X moves right, negative X moves left, positive Y moves down, and negative Y moves up.

Use childrenMargin for item spacing and triggerMargin when the trigger needs different spacing from the menu children.

DropDownMenu(
  controller: controller,
  preset: MenuPreset.bottomCenterOpeningUp,
  childrenMargin: const EdgeInsets.all(8),
  triggerMargin: const EdgeInsets.all(12),
  offset: const Offset(0, -24),
  trigger: (toggleMenu) => IconButton.filled(
    onPressed: toggleMenu,
    icon: const Icon(Icons.menu),
  ),
  children: menuActions,
)

API Reference

BaseMenu

BaseMenu is the shared abstract base for Menu Kit widgets.

  • controller: required AnimationController that drives opening and closing.
  • trigger: required builder that receives VoidCallback toggleMenu.
  • children: required list of menu action widgets.
  • childrenMargin: margin around each child. Defaults to EdgeInsets.all(5).
  • triggerMargin: optional trigger margin. Defaults to childrenMargin.
  • offset: translation applied to the whole menu. Defaults to Offset.zero.

DropDownMenu extends BaseMenu and adds:

  • preset: required MenuPreset that controls anchor and spread direction.

FanMenu

FanMenu extends BaseMenu and adds:

  • preset: required FanMenuPreset that controls the circular or half-curve layout.
  • radius: extra spacing for the fan arc. Defaults to 1.

MenuPreset defines dropdown anchor and direction combinations. Center, edge, corner, and bidirectional presets are available.

FanMenuPreset

FanMenuPreset defines circular and half-curve radial menu arrangements.

Performance Notes

Menu Kit uses Flutter Flow and FlowDelegate, so item positions are painted efficiently during animation without rebuilding every child for every frame. For best results:

  • Reuse one AnimationController per menu instance.
  • Keep menu children lightweight and prefer const widgets where possible.
  • Use stable heroTag values for FloatingActionButton children.
  • Dispose controllers in the owning state object.

License

Menu Kit is available under the MIT License. See LICENSE.

Libraries

Animated dropdown and fan menus for Flutter.