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.

example/lib/main.dart

import 'package:flutter/material.dart';
import 'package:popup_dropdown/popup_dropdown.dart';

void main() => runApp(const MyApp());

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'PopupDropdown Demo',
      theme: ThemeData(
        colorScheme: ColorScheme.fromSeed(seedColor: Colors.indigo),
        useMaterial3: true,
      ),
      home: const ExamplePage(),
    );
  }
}

// ── Sample data models ──────────────────────────────────────────────────────

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

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

// ── Example page ────────────────────────────────────────────────────────────

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

  @override
  State<ExamplePage> createState() => _ExamplePageState();
}

class _ExamplePageState extends State<ExamplePage> {
  final _formKey = GlobalKey<FormState>();

  // State for each example
  String? _selectedFruit;
  Country? _selectedCountry;
  Category? _selectedCategory;
  String? _selectedPriority;
  String? _styledValue;
  String? _validatedValue;

  final _fruits = ['Apple', 'Banana', 'Cherry', 'Date', 'Elderberry', 'Fig'];

  final _countries = [
    const Country('United States', '🇺🇸'),
    const Country('Sri Lanka', '🇱🇰'),
    const Country('United Kingdom', '🇬🇧'),
    const Country('Australia', '🇦🇺'),
    const Country('Japan', '🇯🇵'),
    const Country('Germany', '🇩🇪'),
  ];

  final _categories = [
    const Category(1, 'Electronics', Icons.devices),
    const Category(2, 'Clothing', Icons.checkroom),
    const Category(3, 'Food & Beverage', Icons.restaurant),
    const Category(4, 'Books', Icons.book),
    const Category(5, 'Sports', Icons.sports),
  ];

  final _priorities = ['Low', 'Medium', 'High', 'Critical'];

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('PopupDropdown Examples'),
        backgroundColor: Theme.of(context).colorScheme.inversePrimary,
      ),
      body: Form(
        key: _formKey,
        child: ListView(
          padding: const EdgeInsets.all(20),
          children: [
            _sectionHeader('1 · Basic (String list)'),
            PopupDropdown<String>(
              items: _fruits,
              labelExtractor: (f) => f,
              hint: 'Pick a fruit',
              title: 'Favourite Fruit',
              selectedItem: _selectedFruit,
              onSelected: (v) => setState(() => _selectedFruit = v),
            ),

            _sectionHeader('2 · Object list with leading icon'),
            PopupDropdown<Country>(
              items: _countries,
              labelExtractor: (c) => '${c.flag}  ${c.name}',
              hint: 'Choose country',
              title: 'Country',
              selectedItem: _selectedCountry,
              onSelected: (v) => setState(() => _selectedCountry = v),
            ),

            _sectionHeader('3 · Leading icon builder per item'),
            PopupDropdown<Category>(
              items: _categories,
              labelExtractor: (c) => c.name,
              hint: 'Select category',
              title: 'Category',
              isRequired: true,
              selectedItem: _selectedCategory,
              onSelected: (v) => setState(() => _selectedCategory = v),
              itemLeadingBuilder: (c) => Icon(c.icon, size: 20),
            ),

            _sectionHeader('4 · Custom trailing per item'),
            PopupDropdown<String>(
              items: _priorities,
              labelExtractor: (p) => p,
              hint: 'Select priority',
              title: 'Task Priority',
              selectedItem: _selectedPriority,
              onSelected: (v) => setState(() => _selectedPriority = 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,
                    fontWeight: FontWeight.w600,
                  ),
                ),
              ),
            ),

            _sectionHeader('5 · Custom colours & no dividers'),
            PopupDropdown<String>(
              items: _fruits,
              labelExtractor: (f) => f,
              hint: 'Pick a fruit',
              title: 'Styled Dropdown',
              selectedItem: _styledValue,
              onSelected: (v) => setState(() => _styledValue = v),
              fillColor: Colors.indigo.shade50,
              borderColor: Colors.indigo.shade200,
              focusedBorderColor: Colors.indigo,
              borderRadius: 20,
              height: 52,
              suffixIcon: Icons.expand_more,
              suffixIconColor: Colors.indigo,
              selectedCheckColor: Colors.indigo,
              showDividers: false,
              rotateSuffixIcon: true,
              selectedStyle: const TextStyle(
                color: Colors.indigo,
                fontWeight: FontWeight.w700,
              ),
            ),

            _sectionHeader('6 · Form validation'),
            PopupDropdown<String>(
              items: _fruits,
              labelExtractor: (f) => f,
              hint: 'Required field',
              title: 'Validated Dropdown',
              isRequired: true,
              selectedItem: _validatedValue,
              onSelected: (v) => setState(() => _validatedValue = v),
              validator: (val) =>
                  val == null ? 'Please select an option' : null,
              autovalidateMode: AutovalidateMode.onUserInteraction,
            ),

            const SizedBox(height: 8),
            SizedBox(
              width: double.infinity,
              height: 50,
              child: ElevatedButton(
                onPressed: () {
                  if (_formKey.currentState!.validate()) {
                    ScaffoldMessenger.of(context).showSnackBar(
                      const SnackBar(content: Text('Form is valid! ✅')),
                    );
                  }
                },
                child: const Text('Validate Form'),
              ),
            ),

            _sectionHeader('7 · Disabled state'),
            PopupDropdown<String>(
              items: _fruits,
              labelExtractor: (f) => f,
              hint: 'Cannot open',
              title: 'Disabled',
              selectedItem: 'Banana',
              enabled: false,
            ),

            const SizedBox(height: 40),
          ],
        ),
      ),
    );
  }

  Widget _sectionHeader(String text) {
    return Padding(
      padding: const EdgeInsets.only(top: 4, bottom: 4),
      child: Text(
        text,
        style: TextStyle(
          fontSize: 13,
          fontWeight: FontWeight.w600,
          color: Colors.grey.shade600,
          letterSpacing: 0.3,
        ),
      ),
    );
  }

  Color _priorityColor(String priority) {
    switch (priority) {
      case 'Low':
        return Colors.green;
      case 'Medium':
        return Colors.orange;
      case 'High':
        return Colors.deepOrange;
      case 'Critical':
        return Colors.red;
      default:
        return Colors.grey;
    }
  }
}
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