Skip to content

feat(chip): distinguish flat-mode selected by background color#4956

Open
fabriziocucci wants to merge 1 commit into
callstack:mainfrom
fabriziocucci:feat/chip-flat-selected-background
Open

feat(chip): distinguish flat-mode selected by background color#4956
fabriziocucci wants to merge 1 commit into
callstack:mainfrom
fabriziocucci:feat/chip-flat-selected-background

Conversation

@fabriziocucci
Copy link
Copy Markdown
Contributor

@fabriziocucci fabriziocucci commented May 20, 2026

Summary

Adds visual distinction between selected and unselected flat mode chips. Today Chip mode="flat" renders with theme.colors.secondaryContainer for BOTH the unselected and selected states. Selection is only visible via the check glyph (when showSelectedCheck is set). MD3 spec calls for flat chips to use a transparent fill when unselected and the secondaryContainer token only when selected.

This addresses one bullet from #4931 / discussion #4949 (Chip section):

flat mode background is always secondaryContainer regardless of selected state. Unselected assist/suggestion chips should have no fill (transparent); only selected filter chips use secondaryContainer.

MD3 spec reference: https://m3.material.io/components/chips/specs

Behavior

After the patch, with default props:

Mode Unselected Selected
flat 'transparent' fill theme.colors.secondaryContainer fill
outlined theme.colors.surface fill (unchanged) theme.colors.surface fill (unchanged; outlined chips show selection via the check glyph, not via background change)

Composition with existing props (precedence rules)

  1. customBackgroundColor wins (passed via style={{ backgroundColor: ... }}): an explicit override takes precedence over both the unselected and selected token paths.
  2. disabled wins: disabled tokens take precedence over the selected fill. Flat-disabled-selected returns surfaceContainerLow; outlined-disabled-selected returns 'transparent'. Matches MD3.
  3. No fix-induced behavior change for outlined chips. Outlined-unselected stays surface and outlined-selected stays surface. Outlined chips show selection via the check glyph only, as before.

Implementation

src/components/Chip/helpers.tsx:

  • getDefaultBackgroundColor: flat branch returns 'transparent' (was colors.secondaryContainer).
  • getSelectedBackgroundColor: no longer delegates to getBackgroundColor. New body that branches on disabled, isOutlined and customBackgroundColor to return the correct selected color for each composition.

Net: +18 / -7 lines in helpers.tsx. Outlined mode unchanged. No new public props.

Testing

Visually verified on iOS Simulator (iPhone 17 Pro, iOS 18) and Android Emulator (Pixel 9, API 35) across light and dark themes using a standalone Expo app with the patch applied via patch-package.

Unit tests for the new behavior added in src/components/__tests__/Chip.test.tsx (4 new cases on top of the existing 33):

  • should differ from selectedBackgroundColor for theme version 3, flat mode (the key behavioral contract this PR establishes)
  • should return surface color, for theme version 3, outlined mode (selected, locks down outlined behavior is unchanged)
  • should return disabled fill, for theme version 3, flat mode + disabled (selected, disabled composition)
  • should return transparent for theme version 3, outlined mode + disabled (selected, disabled + outlined composition)

The existing should return theme color, for theme version 3, flat mode (background-color block) was updated to assert 'transparent' instead of secondaryContainer (the test that previously codified the bug).

4 chip snapshots updated (onPress, icon, close button, custom close button) plus 1 ListItem snapshot (it renders a Chip and captured the old background). All 742 unit tests pass.

Screenshots:

iOS

Theme Before After
Light ios-before-light ios-after-light
Dark ios-before-dark ios-after-dark

Android

Theme Before After
Light android-before-light android-after-light
Dark android-before-dark android-after-dark

Observations:

  • The dark-mode "after" screenshots show the same secondaryContainer token but resolved through the dark theme palette. Patch is token-based so any custom theme passed via PaperProvider Just Works.
  • The "flat, no check icon" sandbox row makes the bug most visible: without the check glyph, the BEFORE selected and unselected chips are visually identical.
  • Composition cases (flat + disabled, flat + custom backgroundColor) were each verified visually.

What's NOT in this PR

These were considered and intentionally deferred (each could be its own PR):

Conventional commit

feat(chip): distinguish flat-mode selected by background color

Related

cc @adrcotfas

Copilot AI review requested due to automatic review settings May 20, 2026 10:25
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Updates Chip MD3 color logic so mode="flat" chips use a transparent fill when unselected and theme.colors.secondaryContainer only when selected, aligning selection visibility with MD3 guidance while keeping outlined-chip behavior unchanged.

Changes:

  • Changed default (unselected) flat-chip background from secondaryContainer to 'transparent'.
  • Refactored selected-chip background color selection to explicitly handle disabled/outlined cases and preserve existing outlined behavior.
  • Updated unit tests and snapshots to lock in the new flat/selected background behavior and related compositions.

Reviewed changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated 1 comment.

File Description
src/components/Chip/helpers.tsx Adjusts default and selected background token selection for flat chips.
src/components/__tests__/Chip.test.tsx Adds/updates unit tests covering new background behavior and compositions.
src/components/__tests__/__snapshots__/Chip.test.tsx.snap Updates chip snapshots reflecting transparent unselected flat background.
src/components/__tests__/__snapshots__/ListItem.test.tsx.snap Updates ListItem snapshot impacted by Chip background change.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread src/components/Chip/helpers.tsx Outdated
@callstack-bot
Copy link
Copy Markdown

callstack-bot commented May 20, 2026

Hey @fabriziocucci, thank you for your pull request 🤗. The documentation from this branch can be viewed here.

@fabriziocucci fabriziocucci force-pushed the feat/chip-flat-selected-background branch 3 times, most recently from 2aae75f to 69778fa Compare May 20, 2026 12:17
Flat chips currently render with `theme.colors.secondaryContainer` for
both selected and unselected states. Selection is only visible via the
check glyph (when `showSelectedCheck` is set). MD3 spec requires flat
chips to use a transparent fill when unselected and the
`secondaryContainer` token only when selected.

`src/components/Chip/helpers.tsx`:

- `getDefaultBackgroundColor` flat branch returns `'transparent'`
  (was `colors.secondaryContainer`).
- `getSelectedBackgroundColor` no longer delegates to
  `getBackgroundColor`. It returns `colors.secondaryContainer` for
  flat-selected and `colors.surface` for outlined-selected. `disabled`
  and `customBackgroundColor` overrides take precedence.

Outlined mode is unchanged. Composition with `disabled` and
`customBackgroundColor` is preserved.

Addresses one bullet from callstack#4931 / callstack#4949 (Chip section, "`flat` mode
background is always `secondaryContainer` regardless of `selected`
state"). Verified visually on iOS Simulator and Android Emulator across
light and dark themes.
@fabriziocucci fabriziocucci force-pushed the feat/chip-flat-selected-background branch from 69778fa to d93905a Compare May 20, 2026 12:20
}

return colors.secondaryContainer;
return 'transparent';
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

I think that before changing the background color we should lay the foundation for the updated chips which should be splitting into types - there is no "flat" in the specs.
Also, please double check the specs and visual examples: https://m3.material.io/components/chips/specs.
This PR removes the background from flat chips but there's no equivalent for that in the specs where all chips have at least an outline.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants