Added enabled to DropdownButtonFormField and made onChanged optional
DropdownButtonFormField in material_ui now supports an explicit enabled parameter, and its onChanged callback is no longer required.
Summary
#
In package:material_ui, DropdownButtonFormField now includes
an enabled parameter to explicitly manage its interactive state,
and the onChanged callback is no longer marked as required.
This change is backward compatible, so existing code continues to work.
Background
#
Previously, DropdownButtonFormField didn't have an enabled parameter.
The only way to disable the dropdown
(graying it out and making it non-interactive) was to
pass null to the required onChanged callback.
This led to unintuitive code when trying to
dynamically enable or disable the field,
forcing developers to write conditional expressions for the callback itself,
such as onChanged: condition ? (value) { ... } : null.
To improve this API, a dedicated enabled parameter was introduced,
and onChanged was made optional.
The enabled parameter is optional and
determines the field's interactive state as follows:
-
If
enabledistrue, the field is interactive, even ifonChangedisnull. -
If
enabledisfalse, the field isn't interactive, even ifonChangedis provided. -
If
enabledisn't provided, the field is interactive only ifonChangedisn'tnull, which preserves backward compatibility.
In all of these cases,
the field isn't interactive if items is empty or null.
Migration guide
#
If you previously disabled your DropdownButtonFormField by
conditionally passing null to onChanged,
you can migrate to the new enabled parameter.
This cleanly separates the state of the widget (enabled/disabled) from
its behavior (the callback).
Case 1: Statically disabled dropdown
#
For simple cases where a dropdown is permanently disabled,
you can now simply omit onChanged and use enabled: false.
Code before migration:
final disabledDropdown = DropdownButtonFormField<String>(
initialValue: 'Option 1',
items: const [
DropdownMenuItem(value: 'Option 1', child: Text('Option 1')),
],
onChanged: null, // This was the only way to disable it.
);
Code after migration:
final disabledDropdown = DropdownButtonFormField<String>(
initialValue: 'Option 1',
items: const [
DropdownMenuItem(value: 'Option 1', child: Text('Option 1')),
],
onChanged: null, // This was the only way to disable it.
enabled: false,
);
Case 2: Conditionally disabled dropdown
#
The recommended best practice is to separate the callback from
the interactive state by using the enabled parameter directly.
Remove the condition from onChanged when you add enabled.
If enabled is true and onChanged is null,
users can still change the selection.
The field stores the selected value in its form state and
the parent Form's onChanged callback runs,
but the field has no callback of its own to run.
Code before migration:
final conditionalDropdown = DropdownButtonFormField<String>(
initialValue: 'Option 1',
items: const [
DropdownMenuItem(value: 'Option 1', child: Text('Option 1')),
],
onChanged: condition ? (value) { ... } : null,
);
Code after migration:
final conditionalDropdown = DropdownButtonFormField<String>(
initialValue: 'Option 1',
items: const [
DropdownMenuItem(value: 'Option 1', child: Text('Option 1')),
],
onChanged: condition ? (value) { ... } : null,
onChanged: (value) { ... },
enabled: condition,
);
Timeline
#
Landed in package:material_ui version: 1.8.0
Minimum supported Flutter version: 3.47
References
#API documentation:
Relevant issues:
Relevant PRs:
- Add enabled parameter to DropdownButtonFormField
- Original SDK proposal (closed without merging)
Unless stated otherwise, the documentation on this site reflects Flutter 3.47. Page last updated on 2026-11-09. View source or report an issue.