Skip to content

feat(button): show only the icon and vertical badges in icon-only buttons - #31648

Open
thetaPC wants to merge 24 commits into
FW-6838-badge-spacingfrom
FW-6838-icon-only
Open

thetaPC wants to merge 24 commits into
FW-6838-badge-spacingfrom
FW-6838-icon-only

Conversation

@thetaPC

@thetaPC thetaPC commented Oct 23, 2026

Copy link
Copy Markdown
Contributor

Issue number: resolves internal


What is the current behavior?

An icon-only button renders anything else placed in it: text, icons in the start and end slots, and badges without a vertical position. That content breaks the square shape, as raised in the review of #31043.

What is the new behavior?

  • A button with an icon in the icon-only slot shows only that icon and any badge with a vertical position
  • Text, elements in the start and end slots, and other content are hidden, and the button keeps its square size
  • Hidden text still names the button for assistive technology, so it works like a visually hidden label
  • Text buttons don't change

Does this introduce a breaking change?

  • Yes
  • No

A button with an icon in the icon-only slot now shows only that icon and any badge with a vertical position. Text, elements in the start and end slots, and other content are hidden. Hidden text still names the button for assistive technology. To show other content, remove the icon-only slot and use the start or end slot for the icon.

Other information

Check Before After What to look for
Badges in icon-only buttons Before After In the "badge position: none" sections, icon-only buttons no longer show the badge. In the top and bottom sections, the badges still show

@thetaPC
thetaPC added this pull request to stack #31629 October 23, 2026 23:14
@vercel

vercel Bot commented Oct 23, 2026 •

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated
ionic-framework Ready Ready Preview Oct 29, 2026 6:25pm UTC

Request Review

@thetaPC
thetaPC marked this pull request as ready for review October 29, 2026 16:02
@thetaPC
thetaPC requested a review from a team as a code owner October 29, 2026 16:03
@thetaPC
thetaPC requested a review from ShaneK October 29, 2026 16:03

@ShaneK ShaneK left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Looks good overall, the icon-only sizes hold up across every size and theme! Just a couple of things, mainly wrapped text no longer naming the button for screen readers.

// An icon-only button shows only its icon and badges with a `vertical` position
:host(.button-has-icon-only) ::slotted([slot="start"]),
:host(.button-has-icon-only) ::slotted([slot="end"]),
:host(.button-has-icon-only) ::slotted(:not([slot]):not(ion-badge[vertical])) {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

This one worries me a bit, because text wrapped in an element loses its accessible name now. With <span>Add item</span> or <ion-label>Add item</ion-label> next to the icon, the button has an empty name, where before it was "Add item", and only bare text still works. A visually hidden span is a pretty common way to label an icon button, so could the default-slot elements be visually hidden instead of display: none? If not, BREAKING.md should say only bare text names the button, since right now it says hidden text still does. A test with wrapped text would catch this either way.

}

// An icon-only button shows only its icon and badges with a `vertical` position
:host(.button-has-icon-only) ::slotted([slot="start"]),

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Outside CSS that sets display beats these ::slotted() rules, so the start and end content can come back. In the ionic theme the global link style does it, so <a slot="start" href="#x">Link</a> in an icon-only button still renders, gets its own tab stop, and becomes the button's name. Could we skip rendering the start and end slots when hasIconOnly, or make these !important? An <a slot="start"> case in the tests would cover it.

This branch was successfully deployed

1 active deployment
Preview — 73bcbf1d Deployed Oct 29, 2026 by vercel[bot]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

package: core @ionic/core package

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants