Skip to content

feat(components): add selected icon to ToggleButton - #2017

Draft
ShreyasGit51283 wants to merge 1 commit into
mainfrom
sdeshpande/feat/toggle-button-selected-icon
Draft

feat(components): add selected icon to ToggleButton#2017
ShreyasGit51283 wants to merge 1 commit into
mainfrom
sdeshpande/feat/toggle-button-selected-icon

Conversation

@ShreyasGit51283

@ShreyasGit51283 ShreyasGit51283 commented Aug 27, 2026

Copy link
Copy Markdown
Contributor

Summary

A selected ToggleButton currently reads only from its border and fill. This adds an explicit selection affordance, matching the Figma work in the LaunchPad branch.

Try out the design hereinteractive Storybook for this PR. No checkout or setup needed — click between the options to watch the icon swap.

Two new props on ToggleButton:

  • icon — leading icon shown while the button is not selected.
  • selectedIcon — leading icon shown while it is selected. Defaults to check-circle; pass null to opt out.

The two never render together: selecting a button with a leading icon swaps that icon for check-circle rather than stacking them, so a button shows exactly one icon in either state.

appearance="elevated" defaults selectedIcon to null and shows no icon when selected — its raised surface already makes the selection legible, so a check would be redundant. Passing selectedIcon explicitly still opts back in.

Implementation wraps children in composeRenderProps to read RAC's isSelected render prop, so no new state and no change to the existing class/variant logic. The icon is aria-hidden; selection is still announced through aria-pressed / aria-selected.

Reviewer call-out

This changes rendered output for every existing selected default-appearance toggle button, not just new usages — in gonfalon that includes the access-token status filter and CategoryPills. Two things worth an explicit decision:

  1. Bump level. Filed as minor (additive props, additive behavior), but the repo's rules list "changed default" under major. Happy to re-cut as major if you read it that way.
  2. Width. A selected button is ~20px wider than an unselected one, so segments resize as selection moves. Most visible in narrow groups like 5% / 10% / 50% / 90% / Custom. The design decision so far was to accept this rather than reserve icon space; say the word if you'd prefer it reserved.

Screenshots

Selected state — a selected button that has no icon of its own now shows check-circle. This is the existing ToggleButtonGroupExample story, unchanged apart from the new default:

Selected toggle button showing a check-circle icon

Group where every button has an icon — "First" is selected, so its flask has been replaced by the check, while "Second" and "Third" keep flag and toggle-on. One icon per button in either state, never two:

Toggle button group where every button has an icon and the selected one shows a check instead

Chromatic has the full picture: 14 visual and accessibility changes to accept as baselines, covering every existing story with a selected toggle.

Testing approaches

  • Seven unit tests in ToggleButton.spec.tsx covering: check renders when selected, no icon when unselected, leading icon while unselected, icon-swaps-to-check on selection, custom selectedIcon, selectedIcon={null}, elevated renders nothing, and the icon is aria-hidden.
  • Two new stories in ToggleButtonGroup.stories.tsxSelectedIconSwap (with a play function that clicks through to show the swap) and WithoutSelectedIcon.
  • Doc note on the elevated stories explaining why that appearance opts out.
  • pnpm typecheck, pnpm oxlint:js, pnpm fmt:check clean; all 16 tests across the three toggle specs pass.

Screenshots are hosted on the assets/pr-2017-screenshots branch (images only, never merged) — safe to delete once this lands.

A selected toggle button now shows check-circle, so selection reads at a
glance rather than from the border and fill alone. When a button has a
leading icon, selecting it swaps that icon for the selected one instead of
showing both.

The elevated appearance opts out: its raised surface already signals
selection, so adding an icon there would be redundant.

Co-authored-by: Cursor <cursoragent@cursor.com>
@changeset-bot

changeset-bot Bot commented Aug 27, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: bf9277b

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 1 package
Name Type
@launchpad-ui/components Minor

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@pkg-pr-new

pkg-pr-new Bot commented Aug 27, 2026

Copy link
Copy Markdown
yarn add https://pkg.pr.new/@launchpad-ui/components@2017.tgz
yarn add https://pkg.pr.new/@launchpad-ui/icons@2017.tgz
yarn add https://pkg.pr.new/@launchpad-ui/tokens@2017.tgz

commit: bf9277b

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.

1 participant