flutter
/

Flutter Dropdown – Complete Guide with DropdownButton

Last Sync: Today

On this page

9
0%
5 min read
Remaining
5 minleft

Click any section to jump — progress syncs automatically

flutter

Flutter Dropdown – Complete Guide with DropdownButton

What is a Dropdown in Flutter?

A dropdown is a UI component that allows the user to select one option from a list. In Flutter, you can use DropdownButton for simple selections and DropdownButtonFormField when you need to integrate with a Form (validation, saving). Dropdowns are great for choosing from a limited set of options, such as gender, country, or category.

Basic DropdownButton

A DropdownButton requires three main parameters: value (the currently selected item), items (a list of DropdownMenuItem widgets), and onChanged (a callback that receives the new value).

DARTRead-only
1
String? _selectedItem;

DropdownButton<String>(
  value: _selectedItem,
  hint: Text('Select an option'),
  items: ['Option 1', 'Option 2', 'Option 3'].map((String value) {
    return DropdownMenuItem<String>(
      value: value,
      child: Text(value),
    );
  }).toList(),
  onChanged: (String? newValue) {
    setState(() {
      _selectedItem = newValue;
    });
  },
)

The value must match one of the DropdownMenuItem values, otherwise the dropdown may show nothing or the hint.

Using DropdownMenuItem

DropdownMenuItem is the widget that represents each option. It can contain any widget (e.g., a row with an icon and text).

DARTRead-only
1
DropdownMenuItem<String>(
  value: 'dart',
  child: Row(
    children: [
      Icon(Icons.code),
      SizedBox(width: 8),
      Text('Dart'),
    ],
  ),
)

Customizing Appearance

    • hint: Placeholder text when no value is selected.
    • disabledHint: Hint when the dropdown is disabled.
    • elevation: Elevation of the dropdown menu (shadow).
    • icon: The icon to the right of the selected item.
    • iconSize: Size of the dropdown icon.
    • style: Text style for the selected item.
    • dropdownColor: Background color of the dropdown menu.
    • isExpanded: Whether the dropdown should take the full width of its parent.
DARTRead-only
1
DropdownButton<String>(
  value: _selectedItem,
  hint: Text('Choose'),
  elevation: 8,
  icon: Icon(Icons.arrow_drop_down),
  style: TextStyle(color: Colors.blue, fontSize: 16),
  dropdownColor: Colors.grey.shade100,
  isExpanded: true,
  items: ...
)

DropdownButtonFormField for Forms

DropdownButtonFormField is a wrapper that integrates with Form and provides validation and saving. It works similarly to DropdownButton but adds validator and onSaved callbacks.

DARTRead-only
1
final _formKey = GlobalKey<FormState>();
String? _selectedGender;

Form(
  key: _formKey,
  child: Column(
    children: [
      DropdownButtonFormField<String>(
        value: _selectedGender,
        decoration: InputDecoration(labelText: 'Gender'),
        items: ['Male', 'Female', 'Other'].map((String value) {
          return DropdownMenuItem<String>(
            value: value,
            child: Text(value),
          );
        }).toList(),
        onChanged: (newValue) {
          setState(() => _selectedGender = newValue);
        },
        validator: (value) {
          if (value == null || value.isEmpty) {
            return 'Please select a gender';
          }
          return null;
        },
        onSaved: (value) {
          // Save to a model
        },
      ),
      ElevatedButton(
        onPressed: () {
          if (_formKey.currentState!.validate()) {
            _formKey.currentState!.save();
            // process
          }
        },
        child: Text('Submit'),
      ),
    ],
  ),
)

Dynamic Items from API

You can load dropdown items asynchronously, for example from a REST API. Use FutureBuilder or state management to update the items when data arrives.

DARTRead-only
1
Future<List<String>> fetchCountries() async {
  // simulate network call
  await Future.delayed(Duration(seconds: 1));
  return ['USA', 'Canada', 'UK', 'Germany'];
}

class CountryDropdown extends StatefulWidget {
  @override
  _CountryDropdownState createState() => _CountryDropdownState();
}

class _CountryDropdownState extends State<CountryDropdown> {
  late Future<List<String>> _future;
  String? _selectedCountry;

  @override
  void initState() {
    super.initState();
    _future = fetchCountries();
  }

  @override
  Widget build(BuildContext context) {
    return FutureBuilder<List<String>>(
      future: _future,
      builder: (context, snapshot) {
        if (snapshot.connectionState == ConnectionState.waiting) {
          return CircularProgressIndicator();
        }
        if (snapshot.hasError) {
          return Text('Error: ${snapshot.error}');
        }
        final items = snapshot.data!;
        return DropdownButton<String>(
          value: _selectedCountry,
          hint: Text('Select country'),
          items: items.map((country) {
            return DropdownMenuItem<String>(
              value: country,
              child: Text(country),
            );
          }).toList(),
          onChanged: (value) => setState(() => _selectedCountry = value),
        );
      },
    );
  }
}

Common Mistakes

    • Not providing a value that matches an item: If value is set to a string not in items, the dropdown will show hint or nothing. Ensure value is one of the item values.
    • Forgetting to update value in onChanged: If you don't call setState to update the value, the dropdown won't visually change.
    • Not disposing of controllers: If you use TextEditingController inside dropdown (unlikely), dispose them.
    • Using null as value without a hint: The dropdown will show an empty line; always provide a hint or make sure value is non‑null.
    • Mixing DropdownButtonFormField with Form without a GlobalKey: The form won't be able to validate/save.

Best Practices

    • Use DropdownButtonFormField when you need validation or form integration.
    • Provide a hint to give the user context.
    • For large lists, consider using a searchable dropdown or a modal with a list.
    • Use isExpanded: true to make the dropdown fill available width.
    • Handle null values gracefully; you might allow no selection initially.

Key Takeaways

    • DropdownButton is the basic dropdown widget.
    • DropdownMenuItem defines each option; it can contain any widget.
    • Use value, items, and onChanged to control the dropdown.
    • For forms, use DropdownButtonFormField which adds validation and saving.
    • Items can be built dynamically from data sources.

Try it yourself

import 'package:flutter/material.dart';

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

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Dropdown Demo',
      home: Scaffold(
        appBar: AppBar(title: Text('Dropdown Example')),
        body: Padding(
          padding: const EdgeInsets.all(16.0),
          child: Center(child: DropdownDemo()),
        ),
      ),
    );
  }
}

class DropdownDemo extends StatefulWidget {
  @override
  _DropdownDemoState createState() => _DropdownDemoState();
}

class _DropdownDemoState extends State<DropdownDemo> {
  String? _selectedFruit;
  final List<String> _fruits = ['Apple', 'Banana', 'Orange', 'Mango'];

  @override
  Widget build(BuildContext context) {
    return Column(
      mainAxisAlignment: MainAxisAlignment.center,
      children: [
        DropdownButton<String>(
          value: _selectedFruit,
          hint: Text('Select a fruit'),
          isExpanded: true,
          items: _fruits.map((String fruit) {
            return DropdownMenuItem<String>(
              value: fruit,
              child: Text(fruit),
            );
          }).toList(),
          onChanged: (String? newValue) {
            setState(() {
              _selectedFruit = newValue;
            });
          },
        ),
        SizedBox(height: 20),
        Text('Selected: ${_selectedFruit ?? 'none'}'),
      ],
    );
  }
}

Test Your Knowledge

Q1
of 4

Which widget is used to represent each option in a DropdownButton?

A
DropdownItem
B
MenuItem
C
DropdownMenuItem
D
Option
Q2
of 4

What property controls the currently selected item?

A
selected
B
value
C
initialValue
D
defaultValue
Q3
of 4

How do you make the dropdown expand to the full width of its parent?

A
fullWidth: true
B
isExpanded: true
C
width: double.infinity
D
expand: true
Q4
of 4

Which widget should you use if you need validation in a form?

A
DropdownButton
B
DropdownButtonFormField
C
FormDropdown
D
DropdownFormField

Frequently Asked Questions

How do I set a default value in a DropdownButton?

Set the value property to one of the DropdownMenuItem values. If you want no initial selection, set value to null and provide a hint.

How do I make the dropdown take the full width of its parent?

Set isExpanded: true. The dropdown will expand to fill the available width. For DropdownButtonFormField, you can wrap it in a SizedBox or use decoration's constraints.

How can I create a searchable dropdown?

Flutter doesn't provide a built‑in searchable dropdown. You can use a package like dropdown_search or build your own by combining a TextField with a ListView inside a popup.

What is the difference between `DropdownButton` and `PopupMenuButton`?

DropdownButton is designed for selecting one value from a list and is typically used inline in forms. PopupMenuButton creates a popup menu that appears on tap, often used for actions (like a three‑dot menu). Both have different aesthetics and use cases.

Previous

flutter radio button

Next

flutter http api

Related Content

Need help?

Explore our comprehensive docs or start a chat with our tech experts.