FilteredMenu<T> class

A searchable dropdown menu with keyboard navigation and text filtering.

FilteredMenu combines a text field with a dropdown menu, allowing users to search through options by typing. As the user types, the menu filters to show only matching items. Perfect for large lists where users need to quickly find specific options.

Features

  • Live Search: Filter menu items as you type
  • Keyboard Navigation: Use arrow keys to navigate, Enter to select, Escape to close
  • Auto-Highlighting: Automatically highlights the first matching item
  • Visual Feedback: Highlights current selection and keyboard-focused items
  • Customizable Size: Adjustable height, width, and cursor height

Quick Start

FilteredMenu<String>(
  items: [
    MenuItem(label: 'Apple', value: 'apple'),
    MenuItem(label: 'Banana', value: 'banana'),
    MenuItem(label: 'Cherry', value: 'cherry'),
  ],
  setStateCallback: () => setState(() {}),
  label: 'Select Fruit',
  onSelected: (value) {
    print('Selected: $value');
  },
)

Constructor Parameters

Parameter Type Required Description
items List<MenuItem> Yes List of menu items to display
setStateCallback VoidCallback Yes Callback to trigger parent widget rebuild
initialSelection T? No Value to pre-select when widget loads
onSelected ValueChanged<T?>? No Callback when user selects an item
height double? No Height of the text field (default: 40)
width double? No Width of the text field and dropdown
label String? No Label text displayed above the field
keyboardType TextInputType? No Keyboard type for the text field
cursorHeight double? No Height of the text cursor

Keyboard Shortcuts

  • Arrow Down: Move to next item
  • Arrow Up: Move to previous item
  • Enter: Select highlighted item
  • Escape: Close the dropdown

Filtering Behavior

The menu filters items using case-insensitive substring matching. When you type:

  • Items containing the search text anywhere in their label are shown
  • The first item starting with the search text is automatically highlighted
  • The dropdown scrolls to keep the highlighted item visible

Example with Custom Sizing

FilteredMenu<int>(
  items: List.generate(
    100,
    (i) => MenuItem(label: 'Option ${i + 1}', value: i),
  ),
  setStateCallback: () => setState(() {}),
  height: 50,
  width: 300,
  cursorHeight: 24,
  label: 'Pick a Number',
  initialSelection: 42,
  onSelected: (value) {
    print('You picked: $value');
  },
)

Example with Custom Types

class Product {
  final String name;
  final double price;
  Product(this.name, this.price);
}

FilteredMenu<Product>(
  items: [
    MenuItem(label: 'Laptop', value: Product('Laptop', 999.99)),
    MenuItem(label: 'Mouse', value: Product('Mouse', 29.99)),
    MenuItem(label: 'Keyboard', value: Product('Keyboard', 79.99)),
  ],
  setStateCallback: () => setState(() {}),
  onSelected: (product) {
    if (product != null) {
      print('${product.name}: \$${product.price}');
    }
  },
)

See Also

Inheritance
Available extensions

Constructors

FilteredMenu({Key? key, required List<MenuItem> items, required VoidCallback setStateCallback, String label = '', T? initialSelection, ValueChanged<T?>? onSelected, double? height = 30, double? width = 200, TextInputType? keyboardType, double? cursorHeight, BoxDecoration decoration = const BoxDecoration(), InputDecoration inputDecoration = const InputDecoration()})
const

Properties

cursorHeight double?
final
decoration BoxDecoration
final
hashCode int
The hash code for this object.
no setterinherited
height double?
final
initialSelection → T?
final
inputDecoration InputDecoration
final
items List<MenuItem>
final
key Key?
Controls how one widget replaces another widget in the tree.
finalinherited
keyboardType TextInputType?
final
label String
final
makeRefreshable Widget

Available on Widget?, provided by the WidgetExtension extension

Make your any widget refreshable with RefreshIndicator on top
no setter
onSelected ValueChanged<T?>?
final
runtimeType Type
A representation of the runtime type of the object.
no setterinherited
setStateCallback VoidCallback
final
width double?
final

Methods

center({double? heightFactor, double? widthFactor}) Widget

Available on Widget?, provided by the WidgetExtension extension

set parent widget in center
cornerRadiusWithClipRRect(double radius) ClipRRect

Available on Widget?, provided by the WidgetExtension extension

add corner radius
cornerRadiusWithClipRRectOnly({int bottomLeft = 0, int bottomRight = 0, int topLeft = 0, int topRight = 0}) ClipRRect

Available on Widget?, provided by the WidgetExtension extension

add custom corner radius each side
createElement() StatefulElement
Creates a StatefulElement to manage this widget's location in the tree.
inherited
createState() State<FilteredMenu<T>>
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
expand({int flex = 1}) Widget

Available on Widget?, provided by the WidgetExtension extension

add Expanded to parent widget
fit({BoxFit? fit, AlignmentGeometry? alignment}) Widget

Available on Widget?, provided by the WidgetExtension extension

add FittedBox to parent widget
flexible({int flex = 1, FlexFit? fit}) Widget

Available on Widget?, provided by the WidgetExtension extension

add Flexible to parent widget
noSuchMethod(Invocation invocation) → dynamic
Invoked when a nonexistent method or property is accessed.
inherited
opacity({required double opacity, int durationInSecond = 1, Duration? duration}) Widget

Available on Widget?, provided by the WidgetExtension extension

add opacity to parent widget
paddingAll(double padding) Padding

Available on Widget?, provided by the WidgetExtension extension

return padding all
paddingBottom(double bottom) Padding

Available on Widget?, provided by the WidgetExtension extension

return padding bottom
paddingDirectional({double start = 0.0, double top = 0.0, double end = 0.0, double bottom = 0.0}) Widget

Available on Widget?, provided by the WidgetExtension extension

paddingLeft(double left) Padding

Available on Widget?, provided by the WidgetExtension extension

return padding left
paddingOnly({double top = 0.0, double left = 0.0, double bottom = 0.0, double right = 0.0}) Padding

Available on Widget?, provided by the WidgetExtension extension

return custom padding from each side
paddingRight(double right) Padding

Available on Widget?, provided by the WidgetExtension extension

return padding right
paddingSymmetric({double vertical = 0.0, double horizontal = 0.0}) Padding

Available on Widget?, provided by the WidgetExtension extension

return padding symmetric
paddingTop(double top) Padding

Available on Widget?, provided by the WidgetExtension extension

return padding top
rotate({required double angle, bool transformHitTests = true, Offset? origin}) Widget

Available on Widget?, provided by the WidgetExtension extension

add rotation to parent widget
scale({required double scale, Offset? origin, AlignmentGeometry? alignment, bool transformHitTests = true}) Widget

Available on Widget?, provided by the WidgetExtension extension

add scaling to parent widget
toDiagnosticsNode({String? name, DiagnosticsTreeStyle? style}) DiagnosticsNode
Returns a debug representation of the object that is used by debugging tools and by DiagnosticsNode.toStringDeep.
inherited
tooltip({required String msg}) Widget

Available on Widget?, provided by the WidgetExtension extension

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
translate({required Offset offset, bool transformHitTests = true, Key? key}) Widget

Available on Widget?, provided by the WidgetExtension extension

add translate to parent widget
validate({Widget value = const SizedBox()}) Widget

Available on Widget?, provided by the WidgetExtension extension

Validate given widget is not null and returns given value if null.
visible(bool visible, {Widget? defaultWidget}) Widget

Available on Widget?, provided by the WidgetExtension extension

set visibility
withHeight(double height) SizedBox

Available on Widget?, provided by the WidgetExtension extension

With custom height
withShaderMask(List<Color> colors, {BlendMode blendMode = BlendMode.srcATop}) Widget

Available on Widget?, provided by the WidgetExtension extension

Wrap with ShaderMask widget
withShaderMaskGradient(Gradient gradient, {BlendMode blendMode = BlendMode.srcATop}) Widget

Available on Widget?, provided by the WidgetExtension extension

Wrap with ShaderMask widget Gradient
withSize({double width = 0.0, double height = 0.0}) SizedBox

Available on Widget?, provided by the WidgetExtension extension

With custom height and width
withTooltip({required String msg}) Widget

Available on Widget?, provided by the WidgetExtension extension

Validate given widget is not null and returns given value if null.
withVisibility(bool visible, {Widget? replacement, bool maintainAnimation = false, bool maintainState = false, bool maintainSize = false, bool maintainSemantics = false, bool maintainInteractivity = false}) Visibility

Available on Widget?, provided by the WidgetExtension extension

set widget visibility
withWidth(double width) SizedBox

Available on Widget?, provided by the WidgetExtension extension

With custom width

Operators

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