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
Adds an API example for the Material 3 Expressive `IconButton` support added in #12832, and links it from the `IconButton` docs. The example opts in with `IconButtonThemeData(variant: StyleVariant.material3Expressive)` and shows: * Sizes (`ButtonStyle.sizeVariant`): extra small through extra large * Widths (`ButtonStyle.iconButtonWidth`): narrow, standard, and wide * Shapes (`ButtonStyle.shapeVariant`): round and square, including the shape change when a toggle button is selected * Disabled buttons, unselected and selected It also makes this example the "Icon buttons" entry in the example gallery app (`example/lib/main.dart`), replacing the old `icon_button.3.dart`. | Example | Toggling buttons | | --- | --- | | <img src="https://gist.githubusercontent.com/QuncCccccc/aba2243afce554b515eec724e62e5650/raw/6ea704deaa054fdbeafb58b1836f97ac9751a401/icon_button_m3e_example.png" width="400" alt="Material 3 Expressive IconButton example"> | <img src="https://gist.githubusercontent.com/QuncCccccc/aba2243afce554b515eec724e62e5650/raw/6ea704deaa054fdbeafb58b1836f97ac9751a401/icon_button_m3e_toggle.gif" width="400" alt="Toggling Material 3 Expressive icon buttons"> | Part of flutter/flutter#184940 ## Pre-Review Checklist **Note**: The Flutter team is currently trialing the use of [Gemini Code Assist for GitHub](https://developers.google.com/gemini-code-assist/docs/review-github-code). Comments from the `gemini-code-assist` bot should not be taken as authoritative feedback from the Flutter team. If you find its comments useful you can update your code accordingly, but if you are unsure or disagree with the feedback, please feel free to wait for a Flutter team member's review for guidance on which automated comments should be addressed. [^1]: Regular contributors who have demonstrated familiarity with the repository guidelines only need to comment if the PR is not auto-exempted by repo tooling.
Adds Material 3 Expressive support to `ElevatedButton`. As with `IconButton` (#12832), apps opt in with `ElevatedButtonThemeData(variant: StyleVariant.material3Expressive)`. Without it, `ElevatedButton` keeps the Material 3 style. With Material 3 Expressive, `ElevatedButton` supports: * Sizes (`ButtonStyle.sizeVariant`): extra small through extra large. Each size has its own height, padding, icon size, label text style, and gap between the icon and the label. * Shapes (`ButtonStyle.shapeVariant`): round and square, including the pressed shape and the shape change when a toggle button is selected. * Toggle buttons: a button with a non-null `isSelected` is selectable, and uses the selected colors and selected semantics when `isSelected` is true. The defaults are generated from the Material Design tokens by a new `ButtonTemplateM3E` in `gen_defaults`. New APIs: * `ElevatedButtonThemeData.variant` and `ElevatedButtonTheme.variantOf`. A theme that doesn't specify `variant` inherits it from the enclosing themes, the same way as `IconButtonThemeData.variant` (#13263). * `ButtonStyleButton.isSelected` and `ElevatedButton.isSelected`. * `sizeVariant` and `shapeVariant` parameters for `ElevatedButton.styleFrom`. <img src="https://gist.githubusercontent.com/QuncCccccc/aba2243afce554b515eec724e62e5650/raw/44b10f43dfb6f42d2c0800928d993cec53df15c2/elevated_button_m3e.png" width="320" alt="Material 3 Expressive ElevatedButton sizes, shapes, toggle buttons, and disabled buttons"> Fixes flutter/flutter#194202 Part of flutter/flutter#184937 ## Pre-Review Checklist **Note**: The Flutter team is currently trialing the use of [Gemini Code Assist for GitHub](https://developers.google.com/gemini-code-assist/docs/review-github-code). Comments from the `gemini-code-assist` bot should not be taken as authoritative feedback from the Flutter team. If you find its comments useful you can update your code accordingly, but if you are unsure or disagree with the feedback, please feel free to wait for a Flutter team member's review for guidance on which automated comments should be addressed. [^1]: Regular contributors who have demonstrated familiarity with the repository guidelines only need to comment if the PR is not auto-exempted by repo tooling.
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]///).