Skip to content

feat(label): convert to shadow DOM - #31657

Draft
brandyscarney wants to merge 5 commits into
nextfrom
FW-7102
Draft

brandyscarney wants to merge 5 commits into
nextfrom
FW-7102

Conversation

@brandyscarney

@brandyscarney brandyscarney commented Oct 26, 2026 •

Copy link
Copy Markdown
Member

Issue number: internal


What is the current behavior?

ion-label uses scoped encapsulation.

What is the new behavior?

  • Converts ion-label to Shadow DOM.
  • Label styles only reach direct children through ::slotted(), so heading and paragraph styles now apply to h1-h6 and p elements that are direct children of ion-label.
  • The global heading styles in typography.css and typography.ionic.css now skip headings that are direct children of ion-label, using selectors like h1:where(:not(ion-label > h1)) for each heading level, so the label's heading styles apply to them. The :where() keeps the original specificity.
  • Item now sets the size and margins of stacked, floating and fixed labels, because item's ::slotted(ion-label) styles take precedence over label's own styles in shadow DOM.
  • The disabled label opacity and the skeleton text overflow moved from label to item, because they depend on item state that changes after the label renders.
  • Label checks for an item parent with tag names instead of :host-context, which only Chromium supports in shadow DOM.
  • RTL uses the transform-origin mixin instead of a render-time label-rtl class.
  • Removes legacy :host-context rules for item classes that are no longer set (item-input, item-textarea, item-has-focus, item-has-value, item-has-placeholder), along with the focused and invalid color rules for stacked and floating labels.
  • Updates the component guide with a section on checking a parent's context in shadow components, and rewrites the RTL section to use logical properties, the RTL mixins, or isRTL() checked when needed, instead of render-time classes.

Does this introduce a breaking change?

  • Yes
  • No

BREAKING CHANGE:

ion-label has been converted to use Shadow DOM.

  • Default heading and paragraph styles only apply to h1-h6 and p elements that are direct children of ion-label. Nested headings, such as <ion-label><ion-text><h3>, no longer get label styles and get the global typography instead. Move ion-text inside the heading or paragraph, or set color on ion-label.
  • Global element styles such as h2 { font-size: 20px; } now take precedence over label's heading and paragraph styles. Scope them with h2:not(ion-label > h2) to keep the label styles.
  • App styles that target ion-label directly, such as a class that sets color, now take precedence over the default label styles.

Other information

@vercel

vercel Bot commented Oct 26, 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 27, 2026 2:53pm UTC

Request Review

@brandyscarney brandyscarney changed the title Fw 7102 feat(label): convert to shadow DOM Oct 26, 2026
@github-actions github-actions Bot added the package: core @ionic/core package label Oct 26, 2026
@brandyscarney brandyscarney changed the title feat(label): convert to shadow DOM feat(label): convert to shadow DOM Oct 26, 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.

The 3px comes from the markup change, not the shadow conversion. The h3 used to be the only child of ion-text, so iOS's h3:last-child { margin-bottom: 0 } applied. Shadow DOM can only style direct children, so it's now <h3><ion-text>…</ion-text></h3>. It's no longer a last child, so it keeps its 3px bottom margin. The scoped label renders this markup identically.

<ion-text color="primary">
<h3>H3 Title Text</h3>
</ion-text>
<h3><ion-text color="primary">H3 Title Text</ion-text></h3>

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.

In shadow DOM, label's ::slotted() styles only reach its direct children, so a heading nested inside ion-text loses label's heading styles and gets the global typography instead. Moving ion-text inside the heading keeps the h3 a direct child, so it still gets label's styles. This is documented in BREAKING.md.

This branch was successfully deployed

1 active deployment
Preview — 53e34911 Deployed Oct 27, 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.

1 participant