bouncy_button 2.2.0
bouncy_button: ^2.2.0 copied to clipboard
A customizable 3D push button with async loading states, springs, button groups, and full accessibility, plus a bouncy press effect for any widget.
2.2.0 - 2026-11-03 #
This release goes through a checklist of common button mistakes, and makes each one either impossible or easy to spot.
Added #
timeoutonBouncyButtonandBouncyAsyncBuilder. An action that runs too long shows an error, passes aTimeoutExceptiontoonError, and frees the button and any group lock. Its late result is ignored, but a late error is still reported. Off by default.confirmonBouncyButtonandBouncyAsyncBuilder, asked before the action runs, such as to show a dialog. The action runs only ontrue. While it waits, presses are ignored and no spinner shows.BouncyButton.icon, which requires atooltip, so an icon-only button always has a name. It uses the newBouncyButtonStyle.iconpreset, which is round with a 48 by 48 tap area, orBouncyButtonTheme.iconStyle.isSelectedonBouncyButtonandBouncyPressable, for toggles. Screen readers announce them as checked or not checked.expandedonBouncyButtonandBouncyPressable, for buttons that open a menu or section.BouncyButton.disabledReason, shown as a tooltip and read by screen readers while the button is disabled.statesControlleronBouncyButtonandBouncyPressable, which follows pressed, hovered, focused, disabled, and selected.BouncyButtonStyle.minWidth, a minimum width that still lets longer labels fit.BouncyButtonGroup.showSelectedIconandselectedIcon, which mark selected segments with a check, so the selection doesn't rely on color alone.- Tooltips now also show while a button has keyboard focus.
- Debug-only warnings, printed once each, for an icon-only button with no label, a
semanticLabelthat leaves out the visible text, a tappable widget inside a button, a toggle whose text changes with its state, text below WCAG contrast, a tap area smaller than 48 by 48 (44 by 44 on Apple platforms), and English screen reader labels in an app using another language. Turn them off withdebugBouncyChecksEnabled = false. package:bouncy_button/testing.dartwithexpectAccessibleButton, which checks a button with Flutter's accessibility guidelines and makes sure a double tap and a held Enter key each run it once.flutter_testis now a dependency for it. Release builds don't include it.
Fixed #
- Holding Enter, Space, or another activation key pressed a button over and over, because the app's shortcuts turned each key repeat into another press. It now presses once.
- A button with a controller could report "can only be attached to one widget at a time" when a list moved it to another position.
- When the system asks apps to turn animations off, such as Remove animations on Android, Flutter shortened
cooldown,minLoadingDuration, andresultDurationto 5% of their length, so a 600 millisecond cooldown lasted 30. They now keep their full length. - An
onErrorthat throws no longer leaves a button loading or aBouncyExclusiveScopelocked. Its error is reported to Flutter instead. - The default loading spinner now uses the button's text color. It took the color from outside the button, so it was dark, and hard to see, on dark buttons. Custom
loadingBuilder,successBuilder, anderrorBuildercontent also gets the button's colors now.
Documentation #
- The README is now the full guide. Every feature has a plain-words explanation, when it helps, a code sample, its defaults, what you can change, and a screenshot and GIF, followed by a reference of every option and its default.
- The example app opens on a new Features tab, which shows every feature in the README's order. The README's images are recorded from it with
example/tool/make_gifs.sh.
Changed #
BouncyButtonGroupsegments use checked semantics, as Flutter'sSegmentedButtondoes, so screen readers also announce unselected ones. Tests that looked for a selected flag on a segment should checkisChecked.- The keyboard focus ring is 3 pixels wide instead of 2 in high contrast mode.
2.1.2 - 2026-11-02 #
- The Example tab on pub.dev now shows a one-screen tour of the main features, instead of the demo app's launcher. No code changes.
2.1.1 - 2026-11-02 #
- Rewrote the README: each feature is now explained in plain words with a short example, and the option tables moved to a reference section. No code changes.
2.1.0 - 2026-11-02 #
Added #
cooldownonBouncyButtonandBouncyPressable, which ignores presses for a while after the button is used, so a quick double tap doesn't run an action twice. ForonPressedAsync, it starts once the button is ready again, and errors count too.BouncyAsyncBuilder, which adds double-tap protection and loading, success, and error states to any button, including Material and Cupertino ones. It needs no Material code and is also exported frompackage:bouncy_button/pressable.dart.BouncyButtonController, to press or reset a button from code and follow its status.BouncyExclusiveScope.lockDuringLoading, which lets only one async action below it run at a time.BouncyButtonFeedback.minLoadingDuration, so a very fast action doesn't flash the spinner.BouncyButtonFeedback.loadingText, shown beside the spinner and read by screen readers.BouncyButton.tooltip.- A destructive tone:
BouncyButtonStyle.tonewithBouncyButtonTone.destructive, and aBouncyButtonStyle.destructivepreset. It uses the theme's error colors with every fill. BouncyButtonStyle.minTapTarget, which enlarges the tap area of a small button without changing how it looks.BouncyHapticFeedbackTypeandBouncyGradientExtension, prefixed names that can't clash with other packages.
Deprecated #
HapticFeedbackType, renamedBouncyHapticFeedbackType. The old name still works.GradientExtension, renamedBouncyGradientExtension. Implicit calls such asgradient.scaleLightness(0.5)are unaffected.
Changed #
BouncyButtonStatusmoved to the library's enums, so it is available without Material. Imports ofpackage:bouncy_button/bouncy_button.dartare unaffected.
2.0.0 - 2026-11-02 #
Breaking changes #
- Width: a button with no
widthnow sizes to its child, as the docs always said, instead of filling all available space. To keep a full-width button, setwidth: double.infinityor place it where the parent forces a width, such as insideExpanded. - Height:
BouncyButtonStyle.heightis now a minimum, so the face grows instead of clipping large text. Circular buttons stay exactly this tall. - Dragging: dragging a finger across the button and releasing no longer counts as a press. Press and release is now handled the same way as Material buttons: moving away cancels the press.
- Colors: with no colors set, the face now uses
colorScheme.primaryinstead ofprimaryColor, and text and icons default to a contrasting color. A color set directly on the child still wins. - Long press only: a button with
onLongPressbut noonPressedis now enabled, so it looks enabled and can take focus. It used to render as disabled and ignore the long press. - Nullable fields:
BouncyButton.style,animation, andinteractionare now nullable, because null means "use the theme". BouncyButtonStyle.flatis 46 tall instead of 44, so it reaches the 48px minimum tap target with its elevation.BouncyButtonAnimation.bouncyhas new values and now springs past its resting position on release.bounceanimations now usescaleAmountand stay scaled while held. They used to return to full size during a long hold.hslColornow also paints the face whenbackgroundColoris null.- Requires Flutter 3.27 or later. The old
>=3.10.0constraint was never accurate, because Dart^3.6.0already required it.
Fixed #
- Quick taps now show the full press. Taps shorter than about 100ms used to show no movement at all.
- The button no longer throws inside a
Rowor other parent with unbounded width. BouncyButtonThemenow works. It was documented but never read by the widget.- Enter and Space now activate a focused button, and a focus ring shows during keyboard navigation.
- Disabled buttons can no longer take focus.
- Screen readers now always announce a button, and no longer offer scroll actions on it.
semanticLabelreplaces the child's label instead of being read alongside it. - The system "reduce motion" setting is now respected.
enableSplash: trueno longer removes the press animation and haptics from quick taps.enableSplash: trueno longer throws with aBorderRadiusDirectional.- Disabling a button while it is held no longer throws or leaves it stuck down.
- The button now stays down for the whole of a long press.
- Disabled gradients are now darkened as intended rather than made see-through, and the depth layer matches them.
- Changing
curveat runtime now takes effect. - The default colors no longer make the button invisible on dark themes.
- Animation frames no longer rebuild the button's contents or
builder. pub getis far smaller: the package archive no longer includes the demo GIFs.
Added #
BouncyPressable, which adds the press effect to any widget. It needs no Material code, and is also available on its own frompackage:bouncy_button/pressable.dart.- Nested presses: pressing a button or pressable inside another leaves the outer one still.
BouncyExclusiveScope, which allows only one press at a time below it.BouncyButton.onPressedAsync, which shows a loading state until the returned future completes, then success or an error. The button ignores presses meanwhile, so a form or payment can't be sent twice. Errors go toonError, or toFlutterError.reportError, and are never silently dropped.BouncyButton.isLoading, for loading managed outside the button.BouncyButtonFeedbackto customize loading, success, and error, including the labels screen readers announce. Set it app-wide withBouncyButtonTheme.defaultFeedback.BouncyButton.leading,trailing, andgap, for icons beside the label.BouncyButtonStyle.fillwithBouncyButtonFill.filled,tonal,outlined, andghost, plus matchingtonal,outlined, andghostpresets. Text meets the 4.5:1 contrast minimum in light and dark themes.BouncyButtonStyle.fromSizewithBouncyButtonSize.small,medium, andlarge, which scale height, depth, padding, and text together. Every size is at least 48 pixels tall.BouncyButtonStyle.textStyleandiconSize.BouncyButtonStyle.simple, for quick setup from a color and size, and theshadowLightandshadowDarkconstants.BouncyButtonColors.darkenandlighten.BouncyButtonScope, which themes buttons without the MaterialTheme, for apps usingpackage:material_ui.BouncyButtonThemevalue equality.BouncyPressSpringandBouncyButtonAnimation.spring, for spring physics. Pressing again mid-release reverses smoothly from wherever the button is, keeping its speed. Includessnappy,bouncy, andgentlesprings and aBouncyButtonAnimation.springypreset. Also onBouncyPressable.spring.- Hover lift: with a mouse, the face rises slightly while hovered. Set the height with
BouncyButtonInteraction.hoverLift, or 0 to turn it off. Reduced motion turns it off. BouncyButtonStyle.pressedBorderRadius, which morphs the corners as the button is pressed, such as from a pill or circle to a rounded square.BouncyButtonGroupandBouncyButtonSegment, a row of connected buttons for choosing one option or several. Only the outer corners are rounded, on the correct sides in right-to-left layouts, and screen readers announce which segments are selected.BouncyButtonFill.glassandBouncyButtonStyle.glass, a translucent, blurred face with no depth. It turns solid when the system high contrast setting is on.- Press sounds:
BouncyButtonInteraction.enableSoundplays the system click where the platform has one, andonPressSoundplays your own. Also onBouncyPressable. BouncyButton.tertiary, usingBouncyButtonTheme.tertiaryStyle.BouncyButton.onTapDown,onTapUp,onTapCancel, andhitTestBehavior.BouncyButtonStyle.foregroundColor.BouncyButtonAnimation.reverseDurationandreverseCurve.BouncyButtonInteraction.hoverColorandfocusColor.- Value equality for
BouncyButtonStyle,BouncyButtonAnimation, andBouncyButtonInteraction. GradientExtension.scaleLightness.
Deprecated #
GradientExtension.scale.gradient.scale()always called Flutter's ownGradient.scale, so this method never ran without explicit extension syntax. UsescaleLightness.
1.0.4 - 2025-08-15 #
- Improved documentation
1.0.3 - 2025-08-15 #
- Updated Readme file with png and gif
1.0.2 - 2025-08-15 #
- Minor changes in example app
1.0.1 - 2025-08-15 #
- Added Git Repository Info
1.0.0 - 2025-08-15 #
- Initial release
- 3D depth press effect with customizable elevation
- Multiple animation types (depth, scale, rotation, bounce, fade, slide)
- Extensive styling options with gradients and shadows
- Haptic feedback support
- Theme integration
- Predefined button styles (primary, secondary, flat, pill, circle)
- Color manipulation utilities
- Full accessibility support
- Comprehensive documentation and examples
