Repository navigation
[material_ui] Add Material 3 Expressive IconButton - #12832
Conversation
There was a problem hiding this comment.
Code Review
This pull request introduces Material 3 Expressive support for the IconButton component. It adds new size, width, and shape variants, updates the ButtonStyle class to include these new properties, and implements the necessary defaults in a generated file. A code review comment correctly identified that the generated code uses the deprecated MaterialStatePropertyAll instead of the preferred WidgetStatePropertyAll, which should be updated to ensure modern API usage.
fe2b77a to
e8b4a71
Compare
ba2cfc1 to
7a30d30
Compare
| VisualDensity? get visualDensity => VisualDensity.standard; | ||
|
|
||
| @override | ||
| MaterialTapTargetSize? get tapTargetSize => MaterialTapTargetSize.padded; |
There was a problem hiding this comment.
Should this be Theme.of(context).materialTapTargetSize (to match the M3 implementation)? Here and elsewhere.
There was a problem hiding this comment.
This is intentionally MaterialTapTargetSize.padded rather than Theme.of(context).materialTapTargetSize. M3E defines an extra-small IconButton with a 32dp visual container while retaining a 48dp interaction target. Inheriting materialTapTargetSize: shrinkWrap (the default value on desktop platforms) would reduce that interaction target to 32dp.
This also follows Material’s layout guidance, which specifies that touch targets should remain at least 48×48dp even the visual element is smaller.
| ButtonSizeVariant? sizeVariant, | ||
| IconButtonWidthVariant? iconButtonWidth, | ||
| ButtonShapeVariant? shapeVariant, |
There was a problem hiding this comment.
Should these new properties get added to the button_style_test?
Also should these be WidgetStateProperties? Ooc, what does WidgetStateProperty mean and how do we decide which properties are WidgetStateProperties?
There was a problem hiding this comment.
A WidgetStateProperty represents a value that can resolve differently depending on states such as pressed, hovered, focused, disabled, or selected.
For example, components' overlayColor will change a little bit based on different states, so we will have something like
WidgetStateProperty<Color?>? get overlayColor => WidgetStateProperty.resolveWith((Set<WidgetState> states) {
if (states.contains(WidgetState.selected)) {
if (states.contains(WidgetState.pressed)) {
return _colors.onInverseSurface.withOpacity(0.1);
}
if (states.contains(WidgetState.hovered)) {
return _colors.onInverseSurface.withOpacity(0.08);
}
if (states.contains(WidgetState.focused)) {
return _colors.onInverseSurface.withOpacity(0.08);
}
}
...
});The new properties do not change by widget state. They select a button configuration. For example, ButtonSizeVariant.small selects a coordinated set of values for properties such as ButtonStyle.iconSize, ButtonStyle.padding, ButtonStyle.minimumSize, and ButtonStyle.shape. Those resulting properties are WidgetStatePropertys where state-dependent resolution is needed. Let me know if this doesn't make sense:)!
There was a problem hiding this comment.
Should these new properties get added to the button_style_test?
Added tests!
elliette
left a comment
There was a problem hiding this comment.
LGTM with some comments/questions
flutter/packages@e55e7ac...ba0364a 2026-09-26 stuartmorgan@google.com [google_maps_flutter] Indicate that default iOS impl is discoraged (flutter/packages#12872) 2026-09-26 36861262+QuncCccccc@users.noreply.github.com [material_ui] Add Material 3 Expressive IconButton (flutter/packages#12832) 2026-09-25 jessiewong401@gmail.com Plugin example apps to 9.3.1 (flutter/packages#13019) 2026-09-25 36861262+QuncCccccc@users.noreply.github.com [material_ui] Don't clip MenuItemButton.leadingIcon (flutter/packages#12986) 2026-09-25 36861262+QuncCccccc@users.noreply.github.com [material_ui] Migrate M3 ExpansionTile template to use new gen_defaults (flutter/packages#12920) 2026-09-25 149176071+m1roxx@users.noreply.github.com [two_dimensional_scrollables] Exclude trailing pinned spans from the non-pinned range (flutter/packages#12666) 2026-09-25 36861262+QuncCccccc@users.noreply.github.com [material_ui] Migrate M3 Drawer template to use new gen_defaults (flutter/packages#12916) 2026-09-25 36861262+QuncCccccc@users.noreply.github.com [material_ui] Migrate M3 Divider template to use new gen_defaults (flutter/packages#12915) 2026-09-25 instantni.med@gmail.com [google_maps_flutter_web] Fix AdvancedMarker anchors on web (flutter/packages#11966) If this roll has caused a breakage, revert this CL and set the roller to dry run mode using the controls here: https://autoroll.skia.org/r/flutter-packages-flutter-autoroll Please CC flutter-ecosystem@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://issues.skia.org/issues/new?component=1389291&template=1850622 Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md
This PR is to port #12093 which was created in
m3e_migrationfeature branch.The original PR description
This PR is to add Material 3 Expressive IconButton support behind an explicit component-level opt-in.
This PR adds:
ButtonStyleproperties used by the IconButton M3E migration:sizeVarianticonButtonWidthshapeVariantIconButtonThemeData.variantsoIconButtonscan opt intoStyleVariant.material3Expressive.IconButtonTemplateM3Eto generateIconButtondefaults from the M3E token data.IconButtondefaults in:packages/material_ui/lib/src/generated/icon_button_defaults_m3e.g.dartThemeData.materialTapTargetSizedefaults toshrinkWrapon desktop, so inheriting it would reduce the interaction target to 32dp. M3E therefore defaults toMaterialTapTargetSize.padded. Applications can still override ButtonStyle.tapTargetSize explicitly.TODO:
Pre-Review Checklist
[shared_preferences]///).