Skip to content

[material_ui] Add Material 3 Expressive IconButton - #12832

Merged
auto-submit[bot] merged 37 commits into
flutter:mainfrom
QuncCccccc:icon_button_m3e_main
Sep 26, 2026
Merged

auto-submit[bot] merged 37 commits into
flutter:mainfrom
QuncCccccc:icon_button_m3e_main

Conversation

@QuncCccccc

@QuncCccccc QuncCccccc commented Sep 10, 2026 •

Copy link
Copy Markdown
Contributor

This PR is to port #12093 which was created in m3e_migration feature 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:

  • 3 new ButtonStyle properties used by the IconButton M3E migration:
    • sizeVariant
    • iconButtonWidth
    • shapeVariant
  • IconButtonThemeData.variant so IconButtons can opt into StyleVariant.material3Expressive.
  • IconButtonTemplateM3E to generate IconButton defaults from the M3E token data.
  • Adds the generated M3E IconButton defaults in:
    • packages/material_ui/lib/src/generated/icon_button_defaults_m3e.g.dart
  • Material 3 Expressive defines an extra-small IconButton with a 32dp visual container while retaining a 48dp interaction target. ThemeData.materialTapTargetSize defaults to shrinkWrap on desktop, so inheriting it would reduce the interaction target to 32dp. M3E therefore defaults to MaterialTapTargetSize.padded. Applications can still override ButtonStyle.tapTargetSize explicitly.

TODO:

  • I'll add a separate PR/demo showing the Material 3 Expressive IconButton variants.
  • Will also update IconButton shape morphing to use physics-based motion animation.
image

Pre-Review Checklist

  • I read the [Contributor Guide] and followed the process outlined there for submitting PRs.
  • I read the [AI contribution guidelines] and understand my responsibilities, or I am not using AI tools.
  • I read the [Tree Hygiene] page, which explains my responsibilities.
  • I read and followed the [relevant style guides] and ran [the auto-formatter].
  • I signed the [CLA].
  • The title of the PR starts with the name of the package surrounded by square brackets, e.g. [shared_preferences]
  • I [linked to at least one issue that this PR fixes] in the description above.
  • I followed [the version and CHANGELOG instructions], using [semantic versioning] and the [repository CHANGELOG style], or I have commented below to indicate which documented exception this PR falls under[^1].
  • I updated/added any relevant documentation (doc comments with ///).
  • I added new tests to check the change I am making, or I have commented below to indicate which [test exemption] this PR falls under[^1].
  • All existing and new tests are passing.

@github-actions github-actions Bot added p: material_ui triage-design Should be looked at in design triage labels Sep 10, 2026
@QuncCccccc QuncCccccc changed the title [material_ui] Add Material 3 Expressive IconButton- #12093 [material_ui] Add Material 3 Expressive IconButton Sep 10, 2026
@QuncCccccc
QuncCccccc marked this pull request as ready for review September 10, 2026 23:58
@QuncCccccc QuncCccccc added the CICD Run CI/CD label Sep 10, 2026

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

VisualDensity? get visualDensity => VisualDensity.standard;

@override
MaterialTapTargetSize? get tapTargetSize => MaterialTapTargetSize.padded;

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should this be Theme.of(context).materialTapTargetSize (to match the M3 implementation)? Here and elsewhere.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Comment on lines +551 to +553
ButtonSizeVariant? sizeVariant,
IconButtonWidthVariant? iconButtonWidth,
ButtonShapeVariant? shapeVariant,

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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:)!

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should these new properties get added to the button_style_test?

Added tests!

@elliette elliette left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM with some comments/questions

@QuncCccccc QuncCccccc added the autosubmit Merge PR when tree becomes green via auto submit App label Sep 26, 2026
@auto-submit
auto-submit Bot merged commit 15e15cc into flutter:main Sep 26, 2026
13 checks passed
github-merge-queue Bot pushed a commit to flutter/flutter that referenced this pull request Sep 28, 2026
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
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

autosubmit Merge PR when tree becomes green via auto submit App CICD Run CI/CD p: material_ui triage-design Should be looked at in design triage

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants