Skip to content

fix(input): support floating labels with slotted content - #31309

Merged
brandyscarney merged 41 commits into
major-9.0from
FW-6471-input
Aug 14, 2026
Merged

fix(input): support floating labels with slotted content#31309
brandyscarney merged 41 commits into
major-9.0from
FW-6471-input

Conversation

@brandyscarney

@brandyscarney brandyscarney commented Jul 30, 2026

Copy link
Copy Markdown
Member

Issue number: resolves #29449 resolves #28665


What is the current behavior?

Inputs with a floating label and a start or end slot always display the label in the floated state, regardless of whether the input contains a value:

without value with value
without value with value

What is the new behavior?

  • The floating label now behaves consistently regardless of whether start or end slots are present:
    • It overlays the input when the field is empty.
    • It floats when the input is focused or contains a value.
  • The height of inputs with start or end slots has been reduced to match the md specification.
  • Start slot content is now always positioned to the left of both the label and the input.
  • The clear button is now vertically centered within the entire input container, rather than only the input element.
  • Additional screenshot tests have been added to verify these behavior and layout changes.
  • A follow-up ticket has been created to address the remaining UI differences between our leading/trailing content implementation and the md specification.

Does this introduce a breaking change?

  • Yes
  • No

Floating Label Behavior

Floating labels no longer automatically float when the textarea contains slotted content. Labels float only when the textarea is focused or has a value.

Internal DOM Structure Changes

The internal DOM structure has been reorganized to support floating labels with slotted content.

Added:

  • .input-start
  • .input-control
  • .input-end

Restructured:

  • .label-text-wrapper moved from .input-wrapper into .input-control
  • .native-wrapper moved from .input-wrapper into .input-control
  • Start slot moved from .native-wrapper into .input-start
  • Clear button icon moved from .native-wrapper into .input-end
  • End slot moved from .native-wrapper into .input-end
  • .input-control now contains the label text and native input, while start/end content is separated into dedicated wrappers

Update your selectors to account for these structural changes:

-ion-input .input-wrapper .native-wrapper { }
+ion-input .input-control .native-wrapper { }

-ion-input .input-wrapper .native-wrapper [slot="start"] { }
+ion-input .input-start [slot="start"] { }

-ion-input .input-wrapper .native-wrapper .input-clear-icon { }
+ion-input .input-end .input-clear-icon { }

-ion-input .input-wrapper .native-wrapper [slot="end"] { }
+ion-input .input-end [slot="end"] { }

Other information

Preview

@vercel

vercel Bot commented Jul 30, 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 Aug 14, 2026 1:58pm

Request Review

@github-actions github-actions Bot added the package: core @ionic/core package label Jul 30, 2026

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

I renamed these screenshots from input-slots to input-slot to match the folder name.


configs().forEach(({ title, screenshot, config }) => {
test.describe(title('input: start and end slots (visual checks)'), () => {
test.describe(title('input: slot'), () => {

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

This was updated to match the folder name, following how we title other tests.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

This is the correct height and label position for Material Design filled inputs. See: https://m2.material.io/components/text-fields

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

This 1px shift was caused by the removal of this rule:

/**
* Ensures the input does not
* overlap the label.
*/
:host(.input-label-placement-stacked) input,
:host(.input-label-placement-floating) input {
@include margin(1px, 0, 0, 0);
}

However, this is actually more aligned than before:

Image

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

This 1px shift was caused by the removal of this rule:

/**
* Ensures the input does not
* overlap the label.
*/
:host(.input-label-placement-stacked) input,
:host(.input-label-placement-floating) input {
@include margin(1px, 0, 0, 0);
}

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

This 1px shift was caused by the removal of this rule:

/**
* Ensures the input does not
* overlap the label.
*/
:host(.input-label-placement-stacked) input,
:host(.input-label-placement-floating) input {
@include margin(1px, 0, 0, 0);
}

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

This 1px shift was caused by the removal of this rule:

/**
* Ensures the input does not
* overlap the label.
*/
:host(.input-label-placement-stacked) input,
:host(.input-label-placement-floating) input {
@include margin(1px, 0, 0, 0);
}

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

The clear input button was updated to be vertically centered based on the entire input container. This aligns with how md treats any trailing icon/button:

Image

@brandyscarney brandyscarney changed the title fix(input): float label when start and end slot exist fix(input): support floating labels with slotted content Jul 31, 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.

Looking really great! I just have two remaining suggested changes, one if you want to defer then that's also acceptable

Comment thread core/src/components/input/input.tsx
Comment thread core/src/components/input/input.md.outline.scss

@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 awesome, great work!

@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, minor things but not blockers

Comment thread core/src/utils/forms/start-container-controller.ts
Comment thread core/src/components/input/test/slot/index.html
@brandyscarney
brandyscarney merged commit a292789 into major-9.0 Aug 14, 2026
55 checks passed
@brandyscarney
brandyscarney deleted the FW-6471-input branch August 14, 2026 18:40
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.

4 participants