GlassPopover class

A liquid glass popover that morphs from its trigger button.

GlassPopover implements the same iOS 26 liquid morph animation as GlassMenu, but instead of presenting a list of menu items, it presents any custom widget. Use it for tooltips, mini forms, preview cards, colour pickers, or any content that should appear in a glass overlay.

The popover morphs from the trigger button using spring physics and the dual-blob metaball technique, creating a teardrop expansion effect.

Features

  • Liquid morph animation: Same teardrop physics as GlassMenu
  • Custom content: Any widget, not just menu items
  • Self-closing: Content receives a close callback
  • Auto-positioning: Detects best alignment from trigger position
  • Screen-edge clamping: Keeps popover within safe area
  • Barrier dismissal: Tap outside to close (configurable)
  • Blur ramp: The backdrop blur eases in with the morph instead of paying its full raster cost from the first frame — see blurRampDuration

Usage

Basic Usage

GlassPopover(
  trigger: Icon(CupertinoIcons.info_circle, color: Colors.white),
  contentBuilder: (context, close) => Padding(
    padding: EdgeInsets.all(16),
    child: Text('Hello from the popover!',
      style: TextStyle(color: Colors.white)),
  ),
)

With Interactive Trigger

GlassPopover(
  triggerBuilder: (context, toggle) => GlassButton(
    onTap: toggle,
    child: Text('Show Details'),
  ),
  contentBuilder: (context, close) => Padding(
    padding: EdgeInsets.all(16),
    child: Column(
      mainAxisSize: MainAxisSize.min,
      children: [
        Text('Profile Details', style: TextStyle(color: Colors.white)),
        SizedBox(height: 12),
        GlassButton(onTap: close, child: Text('Done')),
      ],
    ),
  ),
)

With Fixed Height (Scrollable)

GlassPopover(
  popoverHeight: 300,
  trigger: Icon(CupertinoIcons.list_bullet),
  contentBuilder: (context, close) => ListView.builder(
    itemCount: 50,
    itemBuilder: (context, i) => ListTile(title: Text('Item $i')),
  ),
)

Custom Alignment

GlassPopover(
  alignment: GlassMenuAlignment.bottomCenter,
  trigger: Icon(CupertinoIcons.arrow_down),
  contentBuilder: (context, close) => Text('Below the trigger'),
)
Inheritance
Available extensions

Constructors

GlassPopover({Key? key, Widget? trigger, Widget triggerBuilder(BuildContext context, VoidCallback togglePopover)?, required Widget contentBuilder(BuildContext context, VoidCallback close), double popoverWidth = 280, double? popoverHeight, double popoverBorderRadius = 24.0, GlassMenuAlignment? alignment, bool autoAdjustToScreen = true, EdgeInsets screenPadding = const EdgeInsets.all(12), LiquidGlassSettings? settings, GlassQuality? quality, double stretch = 0.3, double interactionScale = 1.02, double stretchResistance = 0.08, Axis? stretchAxis, bool? allowPositiveX, bool? allowNegativeX, bool? allowPositiveY, bool? allowNegativeY, bool enableInteractionGlow = true, bool glowOnTapOnly = true, Color? glowColor, double glowRadius = 0.6, double glowIntensity = 0.0, VoidCallback? onClose, VoidCallback? onOpen, bool barrierDismissible = true, Duration blurRampDuration = const Duration(milliseconds: 260), Curve blurRampCurve = Curves.easeOut, String? semanticLabel})
Creates a liquid glass popover.
const

Properties

alignment → GlassMenuAlignment?
The alignment of the popover relative to the trigger.
final
allowNegativeX → bool?
Whether to allow stretch in the negative X direction (Left). If null, automatically determined by popover position.
final
allowNegativeY → bool?
Whether to allow stretch in the negative Y direction (Up). If null, automatically determined by popover position.
final
allowPositiveX → bool?
Whether to allow stretch in the positive X direction (Right). If null, automatically determined by popover position.
final
allowPositiveY → bool?
Whether to allow stretch in the positive Y direction (Down). If null, automatically determined by popover position.
final
autoAdjustToScreen → bool
Whether to automatically adjust the popover position to keep it on screen.
final
barrierDismissible → bool
Whether tapping outside the popover dismisses it.
final
blurRampCurve → Curve
The easing curve the blur ramp follows from 0 → full strength over blurRampDuration.
final
blurRampDuration → Duration
How long the backdrop blur takes to ramp from 0 up to settings's blur once the popover starts morphing open.
final
contentBuilder → Widget Function(BuildContext context, VoidCallback close)
Builder for the popover content.
final
enableInteractionGlow → bool
Whether to show glow/glare on touch for tactile feedback.
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.
final
hashCode → int
The hash code for this object.
no setterinherited
interactionScale → double
Scale factor applied on touch.
final
key → Key?
Controls how one widget replaces another widget in the tree.
finalinherited
onClose → VoidCallback?
Called when the popover begins closing.
final
onOpen → VoidCallback?
Called when the popover begins opening.
final
popoverBorderRadius → double
Border radius of the expanded popover.
final
popoverHeight → double?
Fixed height for the popover.
final
popoverWidth → double
Width of the expanded popover.
final
quality → GlassQuality?
Rendering quality for the glass effect.
final
runtimeType → Type
A representation of the runtime type of the object.
no setterinherited
screenPadding → EdgeInsets
Minimum distance between the popover and screen edges.
final
semanticLabel → String?
What the trigger opens, announced by screen readers (for example "More actions").
final
settings → LiquidGlassSettings?
Custom glass settings for the popover container.
final
stretch → double
Liquid stretch factor.
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.
final
trigger → Widget?
The widget that triggers the popover.
final
triggerBuilder → Widget Function(BuildContext context, VoidCallback togglePopover)?
A builder for the trigger widget that provides access to the popover toggle callback.
final

Methods

createElement() → StatefulElement
Creates a StatefulElement to manage this widget's location in the tree.
inherited
createState() → State<GlassPopover>
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