popup_dropdown 1.0.0 copy "popup_dropdown: ^1.0.0" to clipboard
popup_dropdown: ^1.0.0 copied to clipboard

A highly customizable popup dropdown widget for Flutter with form validation, animated icon rotation, error states, and zero external dependencies.

popup_dropdown #

A highly customizable popup dropdown widget for Flutter with form validation, animated icon rotation, error states, and zero external dependencies.

pub package

Features #

โœจ Animated icon โ€“ suffix icon rotates when the menu opens
๐ŸŽจ Highly customizable โ€“ 35+ parameters
โœ… Form validation โ€“ plugs directly into Flutter's Form
๐Ÿ”ด Error states โ€“ styled border + error text
๐Ÿ”’ Disabled state โ€“ opacity + no interaction
๐Ÿท๏ธ Leading icons โ€“ custom widget per item
๐Ÿงฉ Custom trailing โ€“ badges, chips, colours per item
๐Ÿช„ Custom child โ€“ fully replace the trigger
๐ŸŒˆ Theme-aware โ€“ respects Material 3 theme
โšก Zero dependencies โ€“ only Flutter


Installation #

dependencies:
  popup_dropdown: ^1.0.0
flutter pub get

Quick Start #

import 'package:popup_dropdown/popup_dropdown.dart';

String? _selected;

PopupDropdown<String>(
  items: ['Apple', 'Banana', 'Cherry'],
  labelExtractor: (item) => item,
  hint: 'Pick a fruit',
  title: 'Favourite Fruit',
  selectedItem: _selected,
  onSelected: (v) => setState(() => _selected = v),
)

Usage Examples #

1 ยท Basic โ€“ string list #

String? _fruit;

PopupDropdown<String>(
  items: ['Apple', 'Banana', 'Cherry'],
  labelExtractor: (item) => item,
  hint: 'Pick a fruit',
  selectedItem: _fruit,
  onSelected: (v) => setState(() => _fruit = v),
)

2 ยท Object list #

class Country {
  final String name;
  final String flag;
  const Country(this.name, this.flag);
}

Country? _country;

PopupDropdown<Country>(
  items: countries,
  labelExtractor: (c) => '${c.flag}  ${c.name}',
  hint: 'Select country',
  title: 'Country',
  selectedItem: _country,
  onSelected: (v) => setState(() => _country = v),
)

3 ยท Leading icon per item #

class Category {
  final String name;
  final IconData icon;
  const Category(this.name, this.icon);
}

PopupDropdown<Category>(
  items: categories,
  labelExtractor: (c) => c.name,
  title: 'Category',
  isRequired: true,
  hint: 'Select category',
  selectedItem: _category,
  onSelected: (v) => setState(() => _category = v),
  itemLeadingBuilder: (c) => Icon(c.icon, size: 20),
)

4 ยท Custom trailing per item (badges / chips) #

PopupDropdown<String>(
  items: ['Low', 'Medium', 'High', 'Critical'],
  labelExtractor: (p) => p,
  hint: 'Select priority',
  title: 'Priority',
  selectedItem: _priority,
  onSelected: (v) => setState(() => _priority = v),
  itemTrailingBuilder: (item, isSelected) => Container(
    padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 2),
    decoration: BoxDecoration(
      color: priorityColor(item).withOpacity(0.15),
      borderRadius: BorderRadius.circular(12),
    ),
    child: Text(
      item,
      style: TextStyle(color: priorityColor(item), fontSize: 11),
    ),
  ),
)

5 ยท Form validation #

final _formKey = GlobalKey<FormState>();
String? _value;

Form(
  key: _formKey,
  child: Column(
    children: [
      PopupDropdown<String>(
        items: options,
        labelExtractor: (i) => i,
        hint: 'Required field',
        title: 'Option',
        isRequired: true,
        selectedItem: _value,
        onSelected: (v) => setState(() => _value = v),
        validator: (val) => val == null ? 'Please select an option' : null,
        autovalidateMode: AutovalidateMode.onUserInteraction,
      ),
      ElevatedButton(
        onPressed: () => _formKey.currentState!.validate(),
        child: const Text('Submit'),
      ),
    ],
  ),
)

6 ยท Custom colours & style #

PopupDropdown<String>(
  items: items,
  labelExtractor: (i) => i,
  hint: 'Pick one',
  selectedItem: _value,
  onSelected: (v) => setState(() => _value = v),

  // Colours
  fillColor: Colors.indigo.shade50,
  borderColor: Colors.indigo.shade200,
  focusedBorderColor: Colors.indigo,
  errorBorderColor: Colors.red.shade300,

  // Shape
  borderRadius: 20,
  height: 52,
  borderWidth: 1.5,

  // Icon
  suffixIcon: Icons.expand_more,
  suffixIconColor: Colors.indigo,
  rotateSuffixIcon: true,

  // Text
  hintStyle: TextStyle(color: Colors.grey.shade400),
  selectedStyle: TextStyle(
    color: Colors.indigo,
    fontWeight: FontWeight.w700,
  ),

  // Menu
  menuColor: Colors.white,
  menuElevation: 8,
  selectedCheckColor: Colors.indigo,
  showDividers: false,
)

7 ยท Custom child trigger #

Replace the default trigger field with any widget:

PopupDropdown<String>(
  items: items,
  labelExtractor: (i) => i,
  hint: 'Pick',
  onSelected: (v) => ...,
  customChild: ElevatedButton.icon(
    onPressed: null, // PopupMenuButton handles the tap
    icon: const Icon(Icons.filter_list),
    label: Text(_value ?? 'Filter'),
  ),
)

8 ยท Disabled state #

PopupDropdown<String>(
  items: items,
  labelExtractor: (i) => i,
  hint: 'Cannot change',
  selectedItem: 'Locked value',
  enabled: false,
  disabledOpacity: 0.5,
  onSelected: (_) {},
)

9 ยท With BLoC / state management #

BlocBuilder<CategoryBloc, CategoryState>(
  builder: (context, state) {
    return PopupDropdown<Category>(
      items: state.categories,
      labelExtractor: (c) => c.name,
      title: 'Category',
      isRequired: true,
      selectedItem: state.selectedCategory,
      hint: 'Choose category',
      onSelected: (c) =>
          context.read<CategoryBloc>().add(CategorySelected(c)),
      validator: (v) => v == null ? 'Required' : null,
    );
  },
)

API Reference #

Required parameters #

Parameter Type Description
items List<T> Items to display
labelExtractor String Function(T) Extracts display string from item

Commonly used optional parameters #

Parameter Type Default Description
selectedItem T? null Currently selected item
onSelected void Function(T)? null Selection callback
hint String 'Select an option' Placeholder text
title String? null Label above the field
isRequired bool false Shows red asterisk
enabled bool true Enable/disable interaction
validator String? Function(T?)? null Form validation
autovalidateMode AutovalidateMode? null When to auto-validate

Styling #

Parameter Type Default Description
fillColor Color? White Field background
borderColor Color? Theme divider Normal border
focusedBorderColor Color? Theme primary Open border
errorBorderColor Color? Theme error Error border
borderRadius double 12.0 Corner radius
borderWidth double? 1.0 / 1.5 Border thickness
height double 56.0 Trigger field height
padding EdgeInsetsGeometry? bottom 20 Outer padding
titleStyle TextStyle? null Label text style
hintStyle TextStyle? null Hint text style
selectedStyle TextStyle? null Selected value style
itemStyle TextStyle? null Item text style
selectedItemStyle TextStyle? null Selected item style in menu

Icon #

Parameter Type Default Description
suffixIcon IconData keyboard_arrow_down_rounded Trailing icon
suffixIconColor Color? Theme hint Icon colour
rotateSuffixIcon bool true Rotate 180ยฐ when open
Parameter Type Default Description
offset Offset Offset(0, 4) Menu position offset
menuConstraints BoxConstraints? null Override menu size
maxMenuHeight double 300 Max popup height
menuColor Color? null Menu background
menuElevation double 3 Menu shadow
itemHeight double 48 Row height
itemPadding EdgeInsetsGeometry Horizontal 16 Row padding
selectedCheckColor Color? Theme primary Check icon colour
showDividers bool true Dividers between items
dividerColor Color? Theme divider Divider colour

Advanced #

Parameter Type Description
customChild Widget? Replace default trigger entirely
itemLeadingBuilder Widget? Function(T)? Leading widget per item
itemTrailingBuilder Widget? Function(T, bool)? Trailing widget per item
disabledOpacity double Opacity when disabled (default 0.6)
onTap VoidCallback? Tap callback when disabled

Common Use Cases #

โœ… Category / product type pickers
โœ… Country / region selection
โœ… Status / priority selectors
โœ… Sort / filter options
โœ… Settings form fields
โœ… Any single-select dropdown


Contributing #

Pull requests are welcome! For major changes, please open an issue first.

License #

MIT โ€” see LICENSE.

2
likes
140
points
51
downloads

Publisher

verified publisherdhananjayafernando.online

Weekly Downloads

A highly customizable popup dropdown widget for Flutter with form validation, animated icon rotation, error states, and zero external dependencies.

Topics

#dropdown #popup #selection #widget #ui

Documentation

API reference

License

MIT (license)

Dependencies

flutter

More

Packages that depend on popup_dropdown