feat: add ConnectedButtonGroup component#5028
Open
matkoson wants to merge 7 commits into
Open
Conversation
…group Introduces ConnectedButtonGroup, the MD3 successor to SegmentedButtons. Selected buttons morph to a fully-rounded shape, the connected inner corners expand on press, and the group supports single- and multi-select across the extra-small to extra-large size scale. Component-specific tokens are extracted into tokens.ts; size, shape and color resolution live in utils.ts. SegmentedButtons is marked as deprecated in favour of the new component.
…ty overlay Pre-blending the disabled container color with color().alpha() breaks on Android dynamic themes where onSurface is a PlatformColor object rather than a string — the fallback rendered a fully opaque near-black container. Apply the MD3 12% disabled opacity as a style on an absolute-fill overlay instead, which works with any ColorValue. Found during on-device Android verification.
- tokens: pressed inner corner now morphs sharper than rest (M3 ConnectedButtonGroup*Tokens: Inner=Small, PressedInner=ExtraSmall), and large/extra-large rest inner corners corrected to large(16)/largeIncreased(20). - press morph: selected buttons also morph on press (pressed precedence over checked, matching Compose ToggleButton); pressOut returns to the rest radius. - accessibility: buttons now use the radio (single-select) / checkbox (multi-select) role instead of button+aria-checked, valid on web and better announced natively. - reduce-motion: shape morph honours the reduce-motion setting (ReduceMotion), matching Switch/FAB. - docs: register ConnectedButtonGroup in component-docs.config so the deprecation link and generated page resolve. - tests: cover shape tokens and role semantics (22 total).
- resolve corner shapes through the shared ShapeToken/resolveCornerRadius from theme/utils/shape instead of a local re-implementation. - drop the per-button rippleColor prop and runtime ripple color derivation; TouchableRipple's stateLayerPressed default applies, consistent with the removal of customRippleColor across components. - expose background and hitSlop passthroughs per button, mirroring SegmentedButtons, and remove the ineffective automatic touch-target expansion. - drive the corner morph with the theme's fast spatial spring (toRawSpring), matching Switch and FAB, instead of timing curves. - add radiogroup semantics to the single-select row and collision-proof list keys. - honour intrinsic button widths in content-sized parents (flexBasis auto). - export ConnectedButtonGroupSize, register a docs screenshot, keep the docs config alphabetical, and extend tests with render snapshots (23).
The docs build requires a committed page under 5.x/docs/components for every entry in component-docs.config; add the ConnectedButtonGroup page (usage, props, theme colors) mirroring SegmentedButtons, regenerate the 6.x content, and point the SegmentedButtons deprecation notice at the correct relative path so the link resolves.
matkoson
marked this pull request as ready for review
July 16, 2026 10:40
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Motivation
The Material Design 3 spec deprecates segmented buttons in favor of the connected button group. This PR adds a
ConnectedButtonGroupcomponent implementing that spec as part of the ongoing modernization effort:buttons/value/onValueChangeAPI shape asSegmentedButtons, easing migration).extra-small→extra-large: 32/40/56/96/136dp) with per-size component tokens extracted intotokens.ts.secondaryContainer/onSecondaryContainer, unselectedsurfaceContainer/onSurfaceVariant, disabledonSurfaceat 12% container / 38% content opacity (applied as styles soPlatformColorthemes work).radio(single-select, inside aradiogrouprow) orcheckbox(multi-select) role with checked/disabled state; per-buttonaria-label, optional selected check icon,hitSlop/backgroundpassthroughs.resolveCornerRadius/ShapeToken,toRawSpring,TouchableRipple'sstateLayerPressedripple default).SegmentedButtonsis marked@deprecatedpointing to this component (non-breaking).Related issue
Fixes #4979
Test plan
yarn typecheck,yarn lint— clean.yarn test ConnectedButtonGroup— 23 tests + 4 render snapshots covering selection (single/multi), sizing, MD3 color roles, disabled behavior, selection check, custom colors, accessibility roles, and shape tokens.