Skip to content

fix(select): prevent floating label and placeholder from overlapping when focused - #31276

Merged
thetaPC merged 5 commits into
ionic-team:mainfrom
droc101:30401
Jul 27, 2026
Merged

fix(select): prevent floating label and placeholder from overlapping when focused#31276
thetaPC merged 5 commits into
ionic-team:mainfrom
droc101:30401

Conversation

@droc101

@droc101 droc101 commented Jul 20, 2026

Copy link
Copy Markdown
Contributor

Issue number: resolves #30401


What is the current behavior?

The floating label and placeholder on ion-select overlap when focused without a value

What is the new behavior?

The placeholder is not shown when a floating label select is focused, as that space is taken up by the label

Does this introduce a breaking change?

  • Yes
  • No

…when focused

modify placeholder visibility (opacity) css condition to show the placeholder if the select is focused *and* has no value, as opposed to only being focused

closes ionic-team#30401
@droc101
droc101 requested a review from a team as a code owner July 20, 2026 16:18
@droc101
droc101 requested a review from thetaPC July 20, 2026 16:18
@vercel

vercel Bot commented Jul 20, 2026

Copy link
Copy Markdown

@droc101 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 Jul 20, 2026
@vercel

vercel Bot commented Jul 20, 2026

Copy link
Copy Markdown

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

Project Deployment Actions Updated (UTC)
ionic-framework Ready Ready Preview, Comment Jul 27, 2026 10:45pm

Request Review

@thetaPC thetaPC left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Please also add a snapshot test under label/select.e2e.ts that captures a focused floating select with a placeholder and no value, so we can verify this state does not regress. Applying the has-focus class directly keeps the screenshot deterministic, following the pattern in the other select e2e tests.

Comment thread core/src/components/select/select.scss Outdated
*/
:host(.select-expanded.select-label-placement-floating) .native-wrapper .select-placeholder,
:host(.has-focus.select-label-placement-floating) .native-wrapper .select-placeholder,
:host(.has-focus.select-label-placement-floating):not(.has-value) .native-wrapper .select-placeholder,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Rather than hiding the placeholder here, let's float the label up on focus instead. This keeps it consistent with ion-input and matches the Material Design text field behavior, where focusing an empty field floats the label and shows the placeholder below.

Take a look at labelShouldFloat in select.tsx for where to handle this.

@droc101

droc101 commented Jul 21, 2026

Copy link
Copy Markdown
Contributor Author

I'll look into adding the test now, but it might take a while as I am not familiar with writing snapshot tests.

Comment on lines +211 to +213
await select.click();
const cancel = page.locator('button.alert-button-role-cancel');
await cancel.click();

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Focus the select's button directly here instead of opening and dismissing the overlay. It reaches the same has-focus state without the overlay animation, so the screenshot stays deterministic, and it drops the dependency on the alert markup.

Suggested change
await select.click();
const cancel = page.locator('button.alert-button-role-cancel');
await cancel.click();
await page.locator('ion-select button').focus();

await select.click();
const cancel = page.locator('button.alert-button-role-cancel');
await cancel.click();
await expect(select).toHaveScreenshot(screenshot(`select-label-focus-floating-no-value-placeholder`));

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Rename this snapshot to select-label-floating-focus-no-value-placeholder so floating comes before focus, matching the other floating snapshots in this file such as select-label-floating-expanded and select-label-floating-long-text. Make sure to delete the old generated snapshots as those don't get automatically deleted when the filename changes.

Suggested change
await expect(select).toHaveScreenshot(screenshot(`select-label-focus-floating-no-value-placeholder`));
await expect(select).toHaveScreenshot(screenshot(`select-label-floating-focus-no-value-placeholder`));

const select = page.locator('ion-select');
await expect(select).toHaveScreenshot(screenshot(`select-label-floating-no-value-placeholder`));
});
test('label should appear on top of the select when it is focused, has a placeholder, and no value', async ({

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

This test only needs to run in MD mode and LTR direction. The label floating on focus does not vary across modes or directions, so scoping it here avoids generating 12 redundant snapshots for a single behavior. Move it into its own config block, matching the pattern in alert/test/basic/alert-tablet.e2e.ts (don't forget the comment block):

/**
 * This behavior does not vary across modes/directions
 */
configs({ modes: ['md'], directions: ['ltr'] }).forEach(({ title, screenshot, config }) => {
  ...
});

@droc101
droc101 requested a review from thetaPC July 27, 2026 18:10

@thetaPC thetaPC left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

LGTM

@thetaPC
thetaPC added this pull request to the merge queue Jul 27, 2026
Merged via the queue into ionic-team:main with commit e987009 Jul 27, 2026
51 checks passed
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 placeholder overlaps label when select has focus and labelPlacement="floating"

2 participants