Skip to content

fix(select): ion-select shows the wrong text for an option with multiple child nodes - #31382

Open
ptmkenny wants to merge 11 commits into
ionic-team:mainfrom
ptmkenny:select-option-text-space
Open

fix(select): ion-select shows the wrong text for an option with multiple child nodes#31382
ptmkenny wants to merge 11 commits into
ionic-team:mainfrom
ptmkenny:select-option-text-space

Conversation

@ptmkenny

Copy link
Copy Markdown
Contributor

Issue number: resolves #31381


What is the current behavior?

ion-select derives the text it displays for the selected option, and that option's
contribution to the button's aria-label, from the option's child nodes. In v9 that
derivation is wrong whenever an option has more than one child node, or has its text
wrapped in an element.

ion-select-option content browser renders v8 v9
Star Star Star Star
two sibling text nodes, {'★'}{'Star'} ★Star ★Star ★ Star
A <b>Star</b> A Star A Star A
<b>Star</b> Star Star (empty)

Two distinct defects:

  1. A space is inserted between adjacent text nodes. Every framework renders
    {icon}{label} as two sibling text nodes with no whitespace between them, so any
    option with an emoji, flag, or icon prefix gains a space that is not in the DOM.

  2. Text wrapped in an element is dropped entirely. An option whose content is
    <b>Star</b>, <span>Star</span>, or an i18n component's wrapper element renders as
    an empty select with an empty accessible name, silently. This is the more damaging
    of the two.

Both affect the visible selected text and the aria-label, and both propagate to every
overlay interface — createAlertInputs, createActionSheetButtons, and
createOverlaySelectOptions read the option through the same helper. In the linked
reproduction, opening the first select shows an alert radio labelled ★ Star.

There is no error or warning; the text is just wrong.

What is the new behavior?

The selected text and aria-label should match what the browser renders for the option's
content, which is what v8 produced via textContent: ★Star for two adjacent text nodes,
and A Star for A <b>Star</b>.

Does this introduce a breaking change?

  • Yes
  • No

(It fixes an unreported breaking change made in #31241)

Other information

@ptmkenny
ptmkenny requested a review from a team as a code owner August 20, 2026 05:18
@ptmkenny
ptmkenny requested a review from BenOsodrac August 20, 2026 05:19
@vercel

vercel Bot commented Aug 20, 2026

Copy link
Copy Markdown

@ptmkenny is attempting to deploy a commit to the Ionic Team on Vercel.

A member of the Team first needs to authorize it.

@github-actions github-actions Bot added the package: core @ionic/core package label Aug 20, 2026

@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.

Nice find, and the diagnosis seems accurate. I agree the element-dropping looks accidental rather than deliberate. Reusing getOptionDefaultSlot is the right call. Plain textContent wouldn't work since it fails your own start/end-slot test, so I think this is about as simple as it gets.

One thing that isn't in the diff: the disabled-config e2e test has a fixture of Full Content plus a span, and this pulls the span's text into the derived text too. It still passes, because the only relevant assertion counts span elements rather than checking the text. I think the new text is right, it's what v8 gave you through textContent, but it does contradict what that test's name implies. @thetaPC could you confirm the intent? Worth adding a text assertion there either way.

Comment thread core/src/components/select/select.tsx Outdated
Comment thread core/src/components/select/test/select.spec.tsx
Comment thread core/src/components/select/select.tsx
Comment thread core/src/components/select/test/select.spec.tsx
@thetaPC

thetaPC commented Aug 20, 2026

Copy link
Copy Markdown
Contributor

@ShaneK Original intent: "only render text nodes" meant don't render markup. When innerHTMLTemplatesEnabled is false, then we shouldn't render HTML of any kind since that markup is potentially harmful. However, ended up being a regression.

This fix is right. Stripping the markup and keeping the text still renders no HTML, so nothing the config protects against changes.

The test should assert that only the default slot text comes through, now Full Content This is a span element, alongside the element counts. Renaming to "should not render markup when innerHTMLTemplatesEnabled is disabled" would stop it being read the way I read it here.

CC: @ptmkenny

@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.

Thanks for turning that around so quickly! Just a few small things this round, and the NBSP one is my fault, sorry!

Comment thread core/src/components/select/select.tsx
Comment thread core/src/components/select/select.tsx Outdated
Comment thread core/src/components/select/select.tsx Outdated
Comment thread core/src/components/select/test/select.spec.tsx Outdated
@ptmkenny

Copy link
Copy Markdown
Contributor Author

@ShaneK Ok, I have reworked this based on the latest feedback and I think it's ready for review again.

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.

bug: ion-select shows the wrong text for an option with multiple child nodes

3 participants