Skip to main content

Module icon_button

Module icon_button 

Source
Expand description

The Material 3 Expressive icon button: 4 variants × 5 sizes × round/ square × 3 widths, with toggle (selected-icon swap), a badge slot, and the same press/hover shape morph crate::button uses.

icon_button builds the default standard icon button; filled_icon_button, tonal_icon_button and outlined_icon_button are the reference’s other three named constructors (IconButtonView::variant switches between them after the fact, mirroring crate::button’s own named-constructor shape). Every one fires on_press on release inside its bounds and leaves its own props alone — is_selected is a caller-owned prop, never self-mutated (docs/CODE_STANDARDS.md’s Interaction Semantics; see Toggle below).

§Relationship to frust::icon_button

Baseline frust-widgets ships its own, much simpler frust::icon_button — a single-variant, transparent-at-rest pressable glyph with no size tiers, no toggle, no badge. This module reuses the same plain icon_button/IconButton names in frust_material on purpose: the established cross-crate naming precedent crate::checkbox/crate::radio already set against their own baseline counterparts. An app picks exactly one by import path (frust_material::icon_button vs. frust::icon_button), never both at the same call site.

§Variants

Container / content roles, from m3e_icon_button_build.dart:153 (_variantColors) — the only table where is_selected changes a color, and only for IconButtonVariant::Standard:

VariantContainerContent
IconButtonVariant::Standard (default)transparentprimary if selected else on_surface_variant
IconButtonVariant::Filledprimaryon_primary
IconButtonVariant::Tonalsecondary_containeron_secondary_container
IconButtonVariant::Outlinedtransparent + outline hairlineprimary

Verified from source, not obvious: unlike crate::button’s resolve_colors, _variantColors carries no disabled branch at all — an icon button built with enabled(false) paints the exact same inks as an enabled one (_morphButtonStyle’s foregroundColor/ backgroundColor resolvers are state-independent constants, bypassing Flutter’s own IconButton disabled dimming). This port matches that exactly: enabled only gates input handling (see Enabled/disabled), never color.

§Sizes and widths

Icon glyph size, and the visual (painted) box vs. the tap-target box, by size × width — m3e_icon_button_theme.dart:39-:101. Visual and target are deliberately distinct measurements: on IconButtonSize::Xs and IconButtonSize::Sm the painted box is smaller than the 48dp minimum touch target, so the outer hit region pads out to 48dp while the visible container stays smaller — from IconButtonSize::Md up, the two already coincide (or the wide variant’s target already exceeds 48dp), so nothing pads further. IconButtonWidget::layout returns the target size and centers the visual box inside it; both are pinned per size in this module’s tests.

SizeIconVisual (default/narrow/wide)Target (default/narrow/wide)
IconButtonSize::Xs2032×32 / 28×32 / 40×3248×48 / 48×48 / 48×48
IconButtonSize::Sm (default)2440×40 / 32×40 / 52×4048×48 / 48×48 / 52×48
IconButtonSize::Md2456×56 / 48×56 / 72×5656×56 / 48×56 / 72×56
IconButtonSize::Lg3296×96 / 64×96 / 128×9696×96 / 64×96 / 128×96
IconButtonSize::Xl40136×136 / 104×136 / 184×136136×136 / 104×136 / 184×136

IconButtonWidth::Standard is the reference’s defaultWidth (renamed to avoid colliding with Rust’s Default trait); IconButtonWidth::Narrow and IconButtonWidth::Wide adjust only the box width, never its height.

§Shape and the press/hover morph

IconButtonShape::Round (the default) and IconButtonShape::Square each resolve a per-size resting radius (m3e_icon_button_theme.dart:103- :117); pressing morphs toward a squarer radius and hovering morphs partway there (m3e_icon_button_shapes.dart:42’s effectiveRadius, :119-:134’s pressed/hovered tables):

SizeRound (rest)Square (rest)HoveredPressed
Xs168106
Sm2010128
Md28141611
Lg48242819
Xl68344027

Unlike crate::button’s own radius tables, none of these four coincide cleanly across every size with frust::Theme’s shape scale (shape_scale()’s small/medium/large/… tokens) — the round table matches at four of five sizes but breaks at Xl (68 has no token), so this module keeps every radius a literal per-size constant rather than a partial, size-inconsistent theme resolution.

The morph itself is [crate::button::motion::RadiusPaddingMotion], reused directly from crate::button — see this module’s RadiusPaddingMotion reuse section — flung along the same named spring [mod@crate::button::motion] uses, crate::tokens::MaterialSpring::EXPRESSIVE_SPATIAL_PRESS (380/0.55).

§RadiusPaddingMotion reuse

crate::button’s RadiusPaddingMotion is the reference’s shared morph primitive (M3ERadiusAndPaddingMotion), used by both the Dart button and icon-button families via one imported file (m3e_icon_buttons.dart:14). This crate’s own port of that primitive lives at button::motion::RadiusPaddingMotion, pub(crate) and now declared inside a pub(crate) mod motion; in button/mod.rs, so this sibling module imports it directly rather than carrying a parallel copy. An earlier version of this module did carry a copy (RadiusMorph) — button/mod.rs’s mod motion; was still private then, and a same-wave task held button/ read-only, so widening it was out of reach; a later task (owning button/ for real) closed that gap by widening the declaration and doing this swap. Every icon-button width/size/variant passes internalLeft/Right/Top/Bottom: 0 to M3ERadiusAndPaddingMotion (m3e_icon_button_build.dart:191-:194), so the padding channel the button family needs never actually moves here — this module pins it to ContentPadding::symmetric(0.0) on every retarget and never reads RadiusPaddingMotion::padding back. press_spring_matches_expressive_spatial_press (this module’s tests) still pins the spring constant this module flings along against crate::button::motion::PRESS_SPRING, now the same constant both families share rather than two copies kept equal by hand.

§Toggle

IconButtonView::selected and IconButtonView::selected_icon together are the reference’s optional toggle pair (isToggle = widget.isSelected != null || widget.selectedIcon != null, m3e_icon_button_build.dart:12-13): a plain icon button sets neither. When toggling, IconButtonShape flips while selected (m3e_icon_button_shapes.dart:16-27’s restVariant) and the active icon becomes selected_icon (falling back to icon if unset) — is_selected is read every build/rebuild as a prop, never written by this widget: a press only ever fires on_press, exactly like every other controlled component in this crate (docs/CODE_STANDARDS.md’s Interaction Semantics).

§Enabled/disabled

IconButtonView::enabled (default true) gates input handling only — see the Variants section above for why colors never dim. A button disabled mid-press drops both the visual press and the pointer capture it was holding, mirroring crate::button’s own rule.

§Badge

IconButtonView::badge ports what _wrapWithBadge/_buildBadge actually paint for this family (m3e_icon_button_build.dart:293-:350) — not the separate, not-yet-built shared badges family this catalog will eventually carry. BadgeValue::Count rounds/clamps to 0..=999_999; 0 paints a small unlabeled dot ([DOT_DIAMETER], the reference’s smallSize: 8); anything else paints a labeled pill. BadgeValue::Text paints a labeled pill directly, or nothing at all for an empty string (v.isEmpty, :332). The pill height/padding are Flutter’s own Badge widget defaults (largeSize/padding, not vendored into this repo’s ported tree, so not line-cited the way every other constant here is) rather than an m3e-specific token. The badge is purely decorative paint, positioned at the visual box’s top-end corner (PositionedDirectional(top: 0, end: 0), :306) — it never hit-tests and never affects layout of anything else.

§Icon color: caller-supplied, not ambient-retinted

The Dart widget wraps its active icon in IconTheme.merge(color: colors.fg, ...) so any descendant Icon inherits the resolved content ink ambiently. This framework has no ambient icon-theme propagation, and crate::button’s own icon child has exactly the same gap (it lays its icon: Option<ChildPod> out at the size token without recoloring it) — this port matches that established precedent rather than inventing one: the icon/selected_icon views a caller supplies are expected to carry their own ink (e.g. frust_material::icons::CHECK built through frust::icon(..).color(..)).

§Not ported in v1

tooltip (no tooltip host in the catalog — the same gap crate::button’s own module doc records), visualSize (a decoration-shaped per-instance override with no builder surface yet), and [M3EIconButtonDecoration]’s gradient fill/overlay/outline seam (the same follow-up shape crate::button’s ButtonDecoration fills for the button family, not yet extended here).

§Attribution

See plugins/material/NOTICE’s “MIT License — Additional Copyright Holders (Vendored Components)” section (Mudit Purohit / icon_button_m3e) and its Module Attribution Header Convention.

Structs§

IconButtonView
A declarative M3 Expressive icon button. See the module docs.
IconButtonWidget
The retained widget for an IconButtonView. See the module docs.

Enums§

BadgeValue
A badge value for IconButtonView::badge — the reference’s Object? badgeValue (a num or a String, m3e_icon_button_build.dart:311-:350), given a closed, typed shape instead.
IconButtonShape
The icon button’s resting shape family — the reference’s M3EIconButtonShapeVariant (m3e_icon_button_enums.dart:32-:38).
IconButtonSize
The icon button’s size tier — the reference’s M3EIconButtonSize (m3e_icon_button_enums.dart:2-:17). See the module docs’ Sizes and widths table.
IconButtonVariant
Which container treatment an icon button paints — the reference’s M3EIconButtonVariant (m3e_icon_button_enums.dart:41-:53). See the module docs’ Variants table.
IconButtonWidth
The icon button’s container width tier — the reference’s M3EIconButtonWidth (m3e_icon_button_enums.dart:20-:29). Self::Standard is the reference’s defaultWidth, renamed to avoid colliding with Rust’s Default trait (see the module docs).

Functions§

IconButton
PascalCase alias for icon_button, matching this catalog’s view-fn vocabulary (Button, AssistChip, …).
filled_icon_button
Create a filled icon button — icon_button with IconButtonVariant::Filled.
icon_button
Create a standard (transparent, on_surface_variant) icon button painting icon, running on_press on release inside its bounds — the reference’s default M3EIconButton.
outlined_icon_button
Create an outlined icon button — icon_button with IconButtonVariant::Outlined.
tonal_icon_button
Create a tonal icon button — icon_button with IconButtonVariant::Tonal.