diff --git a/core/src/components/textarea/test/label-placement/textarea.e2e.ts b/core/src/components/textarea/test/label-placement/textarea.e2e.ts index da18852c18b..7aff19c45c2 100644 --- a/core/src/components/textarea/test/label-placement/textarea.e2e.ts +++ b/core/src/components/textarea/test/label-placement/textarea.e2e.ts @@ -240,3 +240,30 @@ configs({ modes: ['md'], directions: ['ltr'] }).forEach(({ title, screenshot, co }); }); }); + +configs({ modes: ['md'], directions: ['ltr'] }).forEach(({ title, screenshot, config }) => { + test.describe(title('textarea: async label'), () => { + test('textarea should re-render when label slot is added async', async ({ page }) => { + await page.setContent( + ` + + `, + config + ); + + const textarea = page.locator('ion-textarea'); + + await textarea.evaluate((el: HTMLIonInputElement) => { + const labelEl = document.createElement('div'); + labelEl.slot = 'label'; + labelEl.innerHTML = 'Comments *Outline / Floating
Email *
+ +
+

Outline / Floating / Async

+ +
+ + Add Slotted Content + Update Slotted Content + Remove Slotted Content + + diff --git a/core/src/components/textarea/textarea.tsx b/core/src/components/textarea/textarea.tsx index 939bca3b9ea..71973ac9297 100644 --- a/core/src/components/textarea/textarea.tsx +++ b/core/src/components/textarea/textarea.tsx @@ -1,10 +1,25 @@ import type { ComponentInterface, EventEmitter } from '@stencil/core'; -import { Build, Component, Element, Event, Host, Method, Prop, State, Watch, h, writeTask } from '@stencil/core'; +import { + Build, + Component, + Element, + Event, + Host, + Method, + Prop, + State, + Watch, + forceUpdate, + h, + writeTask, +} from '@stencil/core'; import type { LegacyFormController, NotchController } from '@utils/forms'; import { createLegacyFormController, createNotchController } from '@utils/forms'; import type { Attributes } from '@utils/helpers'; import { inheritAriaAttributes, debounceEvent, findItemLabel, inheritAttributes } from '@utils/helpers'; import { printIonWarning } from '@utils/logging'; +import { createSlotMutationController } from '@utils/slot-mutation-controller'; +import type { SlotMutationController } from '@utils/slot-mutation-controller'; import { createColorClasses, hostContext } from '@utils/theme'; import { getIonMode } from '../../global/ionic-global'; @@ -42,6 +57,8 @@ export class Textarea implements ComponentInterface { private legacyFormController!: LegacyFormController; private notchSpacerEl: HTMLElement | undefined; + private slotMutationController?: SlotMutationController; + private notchController?: NotchController; // This flag ensures we log the deprecation warning at most once. @@ -295,6 +312,7 @@ export class Textarea implements ComponentInterface { connectedCallback() { const { el } = this; this.legacyFormController = createLegacyFormController(el); + this.slotMutationController = createSlotMutationController(el, 'label', () => forceUpdate(this)); this.notchController = createNotchController( el, () => this.notchSpacerEl, @@ -320,6 +338,11 @@ export class Textarea implements ComponentInterface { ); } + if (this.slotMutationController) { + this.slotMutationController.destroy(); + this.slotMutationController = undefined; + } + if (this.notchController) { this.notchController.destroy(); this.notchController = undefined;