From d7506ae431d938e02f9be574e8f5073900073db7 Mon Sep 17 00:00:00 2001 From: Feodor Fitsner Date: Thu, 24 Sep 2026 16:30:34 -0700 Subject: [PATCH 1/2] Fix icon-only Button rendering an error box and prepare 1.0.2 Build the plain button with the icon as its child when icon is set without content, instead of the .icon() constructors that require a label. Applies to Button, FilledButton, FilledTonalButton, OutlinedButton and TextButton. Fix #6886 --- CHANGELOG.md | 6 ++++ client/pubspec.lock | 2 +- packages/flet/CHANGELOG.md | 4 +++ packages/flet/lib/src/controls/button.dart | 26 ++++++++---------- packages/flet/pubspec.yaml | 2 +- .../golden/macos/button/icon_only.png | Bin 0 -> 3290 bytes .../golden/macos/filled_button/icon_only.png | Bin 0 -> 2546 bytes .../macos/filled_tonal_button/icon_only.png | Bin 0 -> 2493 bytes .../macos/outlined_button/icon_only.png | Bin 0 -> 3599 bytes .../golden/macos/text_button/icon_only.png | Bin 0 -> 796 bytes .../controls/material/test_button.py | 14 ++++++++++ .../controls/material/test_filled_button.py | 14 ++++++++++ .../material/test_filled_tonal_button.py | 14 ++++++++++ .../controls/material/test_outlined_button.py | 14 ++++++++++ .../controls/material/test_text_button.py | 14 ++++++++++ 15 files changed, 93 insertions(+), 17 deletions(-) create mode 100644 sdk/python/packages/flet/integration_tests/controls/material/golden/macos/button/icon_only.png create mode 100644 sdk/python/packages/flet/integration_tests/controls/material/golden/macos/filled_button/icon_only.png create mode 100644 sdk/python/packages/flet/integration_tests/controls/material/golden/macos/filled_tonal_button/icon_only.png create mode 100644 sdk/python/packages/flet/integration_tests/controls/material/golden/macos/outlined_button/icon_only.png create mode 100644 sdk/python/packages/flet/integration_tests/controls/material/golden/macos/text_button/icon_only.png diff --git a/CHANGELOG.md b/CHANGELOG.md index c4ee25dc62..13dee4c412 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,9 @@ +## 1.0.2 + +### Bug fixes + +* Fix `Button(icon=...)` and other material buttons rendering an error box when `content` is not set. Icon-only buttons now render the icon centered ([#6886](https://github.com/flet-dev/flet/issues/6886)) by @FeodorFitsner. + ## 1.0.1 ### Improvements diff --git a/client/pubspec.lock b/client/pubspec.lock index de454e8440..3e7de10f23 100644 --- a/client/pubspec.lock +++ b/client/pubspec.lock @@ -359,7 +359,7 @@ packages: path: "../packages/flet" relative: true source: path - version: "1.0.1" + version: "1.0.2" flet_ads: dependency: "direct main" description: diff --git a/packages/flet/CHANGELOG.md b/packages/flet/CHANGELOG.md index 16b12d8cc4..106002e7b4 100644 --- a/packages/flet/CHANGELOG.md +++ b/packages/flet/CHANGELOG.md @@ -1,3 +1,7 @@ +## 1.0.2 + +* Fix `Button`, `FilledButton`, `FilledTonalButton`, `OutlinedButton` and `TextButton` rendering an error box when `icon` is set without `content`. `ButtonControl` now uses the `.icon(...)` constructors only when both `icon` and `content` are provided; otherwise it builds the plain button with whichever one is set as its child, so icon-only buttons render the icon centered ([#6886](https://github.com/flet-dev/flet/issues/6886)) by @FeodorFitsner. + ## 1.0.1 _No changes in the `flet` Dart package; version bumped for release coordination with the Python-side fix for child components losing click events after wrapper re-renders ([#6857](https://github.com/flet-dev/flet/issues/6857), [#6859](https://github.com/flet-dev/flet/pull/6859))._ diff --git a/packages/flet/lib/src/controls/button.dart b/packages/flet/lib/src/controls/button.dart index 279e84e93a..db3dad68cb 100644 --- a/packages/flet/lib/src/controls/button.dart +++ b/packages/flet/lib/src/controls/button.dart @@ -7,7 +7,6 @@ import '../utils/colors.dart'; import '../utils/client_actions.dart'; import '../utils/misc.dart'; import '../utils/numbers.dart'; -import '../widgets/error.dart'; import '../widgets/flet_store_mixin.dart'; import 'base_controls.dart'; @@ -112,10 +111,7 @@ class _ButtonControlState extends State with FletStoreMixin { : RoundedRectangleBorder(borderRadius: BorderRadius.circular(4)), ); - Widget error = const ErrorControl("Error displaying Button", - description: "\"icon\" must be specified together with \"content\""); - - if (icon != null) { + if (icon != null && content != null) { if (isFilledButton) { button = FilledButton.icon( style: style, @@ -126,7 +122,7 @@ class _ButtonControlState extends State with FletStoreMixin { onHover: onHoverHandler, clipBehavior: clipBehavior, icon: icon, - label: content ?? error); + label: content); } else if (isFilledTonalButton) { button = FilledButton.tonalIcon( style: style, @@ -137,7 +133,7 @@ class _ButtonControlState extends State with FletStoreMixin { onHover: onHoverHandler, clipBehavior: clipBehavior, icon: icon, - label: content ?? error); + label: content); } else if (isTextButton) { button = TextButton.icon( autofocus: autofocus, @@ -148,7 +144,7 @@ class _ButtonControlState extends State with FletStoreMixin { style: style, clipBehavior: clipBehavior, icon: icon, - label: content ?? error, + label: content, ); } else if (isOutlinedButton) { button = OutlinedButton.icon( @@ -159,7 +155,7 @@ class _ButtonControlState extends State with FletStoreMixin { clipBehavior: clipBehavior, style: style, icon: icon, - label: content ?? error); + label: content); } else { button = ElevatedButton.icon( style: style, @@ -170,7 +166,7 @@ class _ButtonControlState extends State with FletStoreMixin { onHover: onHoverHandler, clipBehavior: clipBehavior, icon: icon, - label: content ?? error); + label: content); } } else { if (isFilledButton) { @@ -182,7 +178,7 @@ class _ButtonControlState extends State with FletStoreMixin { onLongPress: onLongPressHandler, onHover: onHoverHandler, clipBehavior: clipBehavior, - child: content); + child: content ?? icon); } else if (isFilledTonalButton) { button = FilledButton.tonal( style: style, @@ -192,7 +188,7 @@ class _ButtonControlState extends State with FletStoreMixin { onLongPress: onLongPressHandler, onHover: onHoverHandler, clipBehavior: clipBehavior, - child: content); + child: content ?? icon); } else if (isTextButton) { button = TextButton( autofocus: autofocus, @@ -202,7 +198,7 @@ class _ButtonControlState extends State with FletStoreMixin { onLongPress: onLongPressHandler, onHover: onHoverHandler, clipBehavior: clipBehavior, - child: content ?? const Text("")); + child: content ?? icon ?? const Text("")); } else if (isOutlinedButton) { button = OutlinedButton( autofocus: autofocus, @@ -212,7 +208,7 @@ class _ButtonControlState extends State with FletStoreMixin { clipBehavior: clipBehavior, onHover: onHoverHandler, style: style, - child: content); + child: content ?? icon); } else { button = ElevatedButton( style: style, @@ -222,7 +218,7 @@ class _ButtonControlState extends State with FletStoreMixin { onLongPress: onLongPressHandler, onHover: onHoverHandler, clipBehavior: clipBehavior, - child: content); + child: content ?? icon); } } diff --git a/packages/flet/pubspec.yaml b/packages/flet/pubspec.yaml index 5e50506e96..f6b985066b 100644 --- a/packages/flet/pubspec.yaml +++ b/packages/flet/pubspec.yaml @@ -2,7 +2,7 @@ name: flet description: Write entire Flutter app in Python or add server-driven UI experience into existing Flutter app. homepage: https://flet.dev repository: https://github.com/flet-dev/flet/tree/main/packages/flet -version: 1.0.1 +version: 1.0.2 # Supported platforms platforms: diff --git a/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/button/icon_only.png b/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/button/icon_only.png new file mode 100644 index 0000000000000000000000000000000000000000..f252ae5b9ac827ca64d394b1e9beefe35b4b0bea GIT binary patch literal 3290 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 literal 0 HcmV?d00001 diff --git a/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/filled_button/icon_only.png b/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/filled_button/icon_only.png new file mode 100644 index 0000000000000000000000000000000000000000..40c385fc54df06380beddb128b2cd0d4612f9701 GIT binary patch literal 2546 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 literal 0 HcmV?d00001 diff --git a/sdk/python/packages/flet/integration_tests/controls/material/test_button.py b/sdk/python/packages/flet/integration_tests/controls/material/test_button.py index 1787abc7e4..367f360dc7 100644 --- a/sdk/python/packages/flet/integration_tests/controls/material/test_button.py +++ b/sdk/python/packages/flet/integration_tests/controls/material/test_button.py @@ -72,3 +72,17 @@ async def test_style_conflicts(flet_app: ftt.FletTestApp, request): ), ), ) + + +@pytest.mark.asyncio(loop_scope="module") +async def test_icon_only(flet_app: ftt.FletTestApp, request): + flet_app.page.theme_mode = ft.ThemeMode.LIGHT + await flet_app.assert_control_screenshot( + request.node.name, + ft.Row( + controls=[ + ft.Button(icon=ft.Icons.PAUSE), + ft.Button(icon=ft.Icons.PAUSE, icon_color=ft.Colors.RED), + ], + ), + ) diff --git a/sdk/python/packages/flet/integration_tests/controls/material/test_filled_button.py b/sdk/python/packages/flet/integration_tests/controls/material/test_filled_button.py index 84ca94af5a..996fbd9d32 100644 --- a/sdk/python/packages/flet/integration_tests/controls/material/test_filled_button.py +++ b/sdk/python/packages/flet/integration_tests/controls/material/test_filled_button.py @@ -10,3 +10,17 @@ async def test_basic(flet_app: ftt.FletTestApp, request): request.node.name, ft.FilledButton("Click me"), ) + + +@pytest.mark.asyncio(loop_scope="module") +async def test_icon_only(flet_app: ftt.FletTestApp, request): + flet_app.page.theme_mode = ft.ThemeMode.LIGHT + await flet_app.assert_control_screenshot( + request.node.name, + ft.Row( + controls=[ + ft.FilledButton(icon=ft.Icons.PAUSE), + ft.FilledButton(icon=ft.Icons.PAUSE, icon_color=ft.Colors.RED), + ], + ), + ) diff --git a/sdk/python/packages/flet/integration_tests/controls/material/test_filled_tonal_button.py b/sdk/python/packages/flet/integration_tests/controls/material/test_filled_tonal_button.py index b7ec452f08..72ec2bf5ea 100644 --- a/sdk/python/packages/flet/integration_tests/controls/material/test_filled_tonal_button.py +++ b/sdk/python/packages/flet/integration_tests/controls/material/test_filled_tonal_button.py @@ -10,3 +10,17 @@ async def test_basic(flet_app: ftt.FletTestApp, request): request.node.name, ft.FilledTonalButton("Click me"), ) + + +@pytest.mark.asyncio(loop_scope="module") +async def test_icon_only(flet_app: ftt.FletTestApp, request): + flet_app.page.theme_mode = ft.ThemeMode.LIGHT + await flet_app.assert_control_screenshot( + request.node.name, + ft.Row( + controls=[ + ft.FilledTonalButton(icon=ft.Icons.PAUSE), + ft.FilledTonalButton(icon=ft.Icons.PAUSE, icon_color=ft.Colors.RED), + ], + ), + ) diff --git a/sdk/python/packages/flet/integration_tests/controls/material/test_outlined_button.py b/sdk/python/packages/flet/integration_tests/controls/material/test_outlined_button.py index d162c6f2ca..97553a4845 100644 --- a/sdk/python/packages/flet/integration_tests/controls/material/test_outlined_button.py +++ b/sdk/python/packages/flet/integration_tests/controls/material/test_outlined_button.py @@ -10,3 +10,17 @@ async def test_basic(flet_app: ftt.FletTestApp, request): request.node.name, ft.OutlinedButton("Click me"), ) + + +@pytest.mark.asyncio(loop_scope="module") +async def test_icon_only(flet_app: ftt.FletTestApp, request): + flet_app.page.theme_mode = ft.ThemeMode.LIGHT + await flet_app.assert_control_screenshot( + request.node.name, + ft.Row( + controls=[ + ft.OutlinedButton(icon=ft.Icons.PAUSE), + ft.OutlinedButton(icon=ft.Icons.PAUSE, icon_color=ft.Colors.RED), + ], + ), + ) diff --git a/sdk/python/packages/flet/integration_tests/controls/material/test_text_button.py b/sdk/python/packages/flet/integration_tests/controls/material/test_text_button.py index 12a61c379d..67f47b9fbb 100644 --- a/sdk/python/packages/flet/integration_tests/controls/material/test_text_button.py +++ b/sdk/python/packages/flet/integration_tests/controls/material/test_text_button.py @@ -10,3 +10,17 @@ async def test_basic(flet_app: ftt.FletTestApp, request): request.node.name, ft.TextButton("Click me"), ) + + +@pytest.mark.asyncio(loop_scope="module") +async def test_icon_only(flet_app: ftt.FletTestApp, request): + flet_app.page.theme_mode = ft.ThemeMode.LIGHT + await flet_app.assert_control_screenshot( + request.node.name, + ft.Row( + controls=[ + ft.TextButton(icon=ft.Icons.PAUSE), + ft.TextButton(icon=ft.Icons.PAUSE, icon_color=ft.Colors.RED), + ], + ), + ) From 0de4ffbaaba3952a032f4f9d860c5f2a3b58b9ff Mon Sep 17 00:00:00 2001 From: Feodor Fitsner Date: Thu, 24 Sep 2026 16:30:51 -0700 Subject: [PATCH 2/2] Link icon-only Button fix PR in changelogs --- CHANGELOG.md | 2 +- packages/flet/CHANGELOG.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 13dee4c412..cee37ee30f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,7 +2,7 @@ ### Bug fixes -* Fix `Button(icon=...)` and other material buttons rendering an error box when `content` is not set. Icon-only buttons now render the icon centered ([#6886](https://github.com/flet-dev/flet/issues/6886)) by @FeodorFitsner. +* Fix `Button(icon=...)` and other material buttons rendering an error box when `content` is not set. Icon-only buttons now render the icon centered ([#6886](https://github.com/flet-dev/flet/issues/6886), [#6889](https://github.com/flet-dev/flet/pull/6889)) by @FeodorFitsner. ## 1.0.1 diff --git a/packages/flet/CHANGELOG.md b/packages/flet/CHANGELOG.md index 106002e7b4..9ed14cc35a 100644 --- a/packages/flet/CHANGELOG.md +++ b/packages/flet/CHANGELOG.md @@ -1,6 +1,6 @@ ## 1.0.2 -* Fix `Button`, `FilledButton`, `FilledTonalButton`, `OutlinedButton` and `TextButton` rendering an error box when `icon` is set without `content`. `ButtonControl` now uses the `.icon(...)` constructors only when both `icon` and `content` are provided; otherwise it builds the plain button with whichever one is set as its child, so icon-only buttons render the icon centered ([#6886](https://github.com/flet-dev/flet/issues/6886)) by @FeodorFitsner. +* Fix `Button`, `FilledButton`, `FilledTonalButton`, `OutlinedButton` and `TextButton` rendering an error box when `icon` is set without `content`. `ButtonControl` now uses the `.icon(...)` constructors only when both `icon` and `content` are provided; otherwise it builds the plain button with whichever one is set as its child, so icon-only buttons render the icon centered ([#6886](https://github.com/flet-dev/flet/issues/6886), [#6889](https://github.com/flet-dev/flet/pull/6889)) by @FeodorFitsner. ## 1.0.1