GlassMenu class

A liquid glass context menu that morphs from its trigger button.

GlassMenu implements the iOS 26 "liquid glass" morphing pattern where a button seamlessly transforms into a menu. The same glass container transitions between button and menu states using spring physics.

Features

  • True morphing: Button transforms into menu (not overlay)
  • Smooth spring physics: Gentle settle with no harsh bounces (stiffness: 300, damping: 24)
  • Liquid swoop: Subtle 5px parabolic arc for seamless down-and-up motion
  • Seamless crossfade: Button only appears at final 5% to preserve morph illusion
  • Dimension interpolation: Width, height, and border radius morph smoothly
  • Position aware: Menu expands from button position
  • Settings inheritance: Inherits parent layer settings like GlassContainer.card (thin rim by default)
  • No button animation: Trigger button remains static, only shape morphs
Inheritance
Available extensions

Constructors

GlassMenu({Key? key, Widget? trigger, Widget triggerBuilder(BuildContext context, VoidCallback toggleMenu)?, required List<Widget> items, GlassMenuAlignment? menuAlignment, bool autoAdjustToScreen = false, double menuWidth = 200, double menuBorderRadius = 32.0, double itemBorderRadius = 24.0, LiquidGlassSettings? settings, GlassQuality? quality, double stretch = 0.5, double interactionScale = 1.02, double stretchResistance = 0.08, Axis? stretchAxis, bool? allowPositiveX, bool? allowNegativeX, bool? allowPositiveY, bool? allowNegativeY, double? menuHeight, double? maxStackHeight, EdgeInsets menuPadding = EdgeInsets.zero, Color selectionColor = const Color(0x3DFFFFFF), bool enableInteractionGlow = true, bool glowOnTapOnly = false, Color? glowColor, double glowRadius = 0.6, double glowIntensity = 0.0, VoidCallback? onClose, GlassMenuController? controller, bool showDismissBarrier = true, bool morphFromZero = false, bool platformViewBackdrop = false, MorphSpeed morphSpeed = MorphSpeed.normal, bool enableContinuousSwipe = false, double continuousSwipeSlop = 10.0, String? semanticLabel, void onLevelChanged(int depth, double height)?})
Creates a liquid glass menu.
const

Properties

allowNegativeX → bool?
Whether to allow stretch in the negative X direction (Left). If null, automatically determined by menu position.
final
allowNegativeY → bool?
Whether to allow stretch in the negative Y direction (Up). If null, automatically determined by menu position.
final
allowPositiveX → bool?
Whether to allow stretch in the positive X direction (Right). If null, automatically determined by menu position.
final
allowPositiveY → bool?
Whether to allow stretch in the positive Y direction (Down). If null, automatically determined by menu position.
final
autoAdjustToScreen → bool
Whether to automatically adjust the menu position to keep it on screen.
final
continuousSwipeSlop → double
The movement threshold in logical pixels required to arm continuous swipe.
final
controller → GlassMenuController?
Optional controller to drive the menu imperatively (GlassMenuController.open / GlassMenuController.close) instead of — or in addition to — tapping the trigger.
final
enableContinuousSwipe → bool
Whether to enable iOS-style continuous swipe-to-select.
final
enableInteractionGlow → bool
Whether to show glow/glare on touch for tactile feedback. Default: true.
final
glowColor → Color?
Custom color for the touch interaction glow.
final
glowIntensity → double
The intensity of the interactive glow.
final
glowOnTapOnly → bool
Whether the glow should act as a momentary tap indicator.
final
glowRadius → double
Radius of the touch interaction glow. Default: 0.6.
final
hashCode → int
The hash code for this object.
no setterinherited
interactionScale → double
Scale factor applied on touch. Default: 1.02.
final
itemBorderRadius → double
Border radius of the selection highlight and menu items.
final
items → List<Widget>
The list of items to display in the menu.
final
key → Key?
Controls how one widget replaces another widget in the tree.
finalinherited
maxStackHeight → double?
Maximum vertical extent of the root and all layered submenu cards.
final
The alignment of the menu relative to the trigger.
final
Border radius of the expanded menu.
final
Optional fixed height for the menu.
final
The minimum distance between the menu and the screen edges.
final
Width of the expanded menu.
final
morphFromZero → bool
Whether the open/close morph blooms from a zero-size point at the trigger center instead of from a glass blob the size of the trigger. Defaults to false (the menu spawns as a small rounded "metaball" matching the trigger and morphs outward — the standard iOS-26 liquid-glass behavior).
final
morphSpeed → MorphSpeed
Speed profile for the open/close morph animation.
final
onClose → VoidCallback?
Called when the menu begins closing.
final
onLevelChanged → void Function(int depth, double height)?
Called with the submenu depth (0 = root list) and the resting height of the whole visible stack — the menu body, plus every open submenu card that extends past it — whenever the stack changes: when the menu opens, and on every GlassMenuItem.submenu push or header pop, just before the layering morph animates.
final
platformViewBackdrop → bool
When true (typically for iOS PlatformViews), forces the BackdropFilter fallback render path instead of the Impeller-native shader. Forwarded to the underlying AdaptiveLiquidGlassLayer.
final
quality → GlassQuality?
Rendering quality for the glass effect.
final
runtimeType → Type
A representation of the runtime type of the object.
no setterinherited
selectionColor → Color
Custom color for the menu selection background.
final
semanticLabel → String?
What the trigger opens, announced by screen readers (for example "More actions").
final
settings → LiquidGlassSettings?
Custom glass settings for the menu container.
final
showDismissBarrier → bool
Whether to render the full-screen tap-to-dismiss barrier behind the open menu. Defaults to true (modal: a tap outside the menu closes it).
final
stretch → double
Liquid stretch factor. Default: 0.5.
final
stretchAxis → Axis?
The axis to constrain the stretch to. If null, stretches in both axes.
final
stretchResistance → double
The resistance factor to apply to the drag offset. Higher values make the drag feel "stickier". Default: 0.08.
final
trigger → Widget?
The widget that triggers the menu.
final
triggerBuilder → Widget Function(BuildContext context, VoidCallback toggleMenu)?
A builder for the trigger widget that provides access to the menu toggle callback.
final

Methods

createElement() → StatefulElement
Creates a StatefulElement to manage this widget's location in the tree.
inherited
createState() → State<GlassMenu>
Creates the mutable state for this widget at a given location in the tree.
override
debugDescribeChildren() → List<DiagnosticsNode>
Returns a list of DiagnosticsNode objects describing this node's children.
inherited
debugFillProperties(DiagnosticPropertiesBuilder properties) → void
Add additional properties associated with the node.
inherited
glassContextMenu({Key? key, required List<Widget> actions, WidgetBuilder? previewBuilder, bool enabled = true, bool enableHaptics = true, double borderRadius = 32.0, double? previewBorderRadius, double rowBorderRadius = 16.0, BorderRadius? rowCorners, Color? originSlotColor, Color? backgroundColor, LiquidGlassSettings? settings, GlassQuality? quality, double backdropBlur = 0.0, Color? barrierColor, double menuWidth = 250.0, VoidCallback? onOpened, VoidCallback? onDismissed, Duration longPressDuration = const Duration(milliseconds: 700)}) → Widget

Available on Widget, provided by the GlassContextMenuExtension extension

Wraps this widget in a GlassContextMenu displaying actions on long-press or right-click.
glassFullScreenCover({required bool isPresented, VoidCallback? onDismiss, required WidgetBuilder content, bool enableSwipeToDismiss = true, double dismissThreshold = 140.0, LiquidGlassSettings? settings, GlassQuality? quality}) → Widget

Available on Widget, provided by the GlassFullScreenCoverExtension extension

Presents a full-viewport modal cover whenever isPresented is true.

Available on Widget, provided by the GlassNavigationTitleExtension extension

Annotates this widget with a navigation title that drives enclosing or descendant GlassAppBar / GlassAppBar.pinned bars (when their explicit title is null) as well as header accessibility semantics.
noSuchMethod(Invocation invocation) → dynamic
Invoked when a nonexistent method or property is accessed.
inherited
toDiagnosticsNode({String? name, DiagnosticsTreeStyle? style}) → DiagnosticsNode
Returns a debug representation of the object that is used by debugging tools and by DiagnosticsNode.toStringDeep.
inherited
toString({DiagnosticLevel minLevel = DiagnosticLevel.info}) → String
A string representation of this object.
inherited
toStringDeep({String prefixLineOne = '', String? prefixOtherLines, DiagnosticLevel minLevel = DiagnosticLevel.debug, int wrapWidth = 65}) → String
Returns a string representation of this node and its descendants.
inherited
toStringShallow({String joiner = ', ', DiagnosticLevel minLevel = DiagnosticLevel.debug}) → String
Returns a one-line detailed description of the object.
inherited
toStringShort() → String
A short, textual description of this widget.
inherited

Operators

operator ==(Object other) → bool
The equality operator.
inherited