Skip to content

Commit 6cbb09a

Browse files
fix(textarea): fix helper-text "max-width: 0px" on hidden render (#20429)
* test: add test case stories * chore: wc test story * fix(react): fix wrapper width via resizeObserver * test(wc): add test with tab story * fix(wc): fix wrapper width via resizeObserver * chore: cleanup * Update packages/react/src/components/TextArea/TextArea.tsx Co-authored-by: Taylor Jones <tay1orjones@users.noreply.github.com> * chore: remove test stories --------- Co-authored-by: Taylor Jones <tay1orjones@users.noreply.github.com>
1 parent 650edbf commit 6cbb09a

File tree

2 files changed

+34
-13
lines changed

2 files changed

+34
-13
lines changed

packages/react/src/components/TextArea/TextArea.tsx

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -226,19 +226,29 @@ const TextArea = frFn((props, forwardRef) => {
226226
}, [value, defaultValue, counterMode]);
227227

228228
useIsomorphicEffect(() => {
229-
const measuredWidth = wrapperRef.current?.scrollWidth;
230229
if (other.cols && textareaRef.current) {
231230
textareaRef.current.style.width = '';
232231
textareaRef.current.style.resize = 'none';
233232
} else if (textareaRef.current) {
234233
textareaRef.current.style.width = `100%`;
235234
}
236-
[helperTextRef, errorTextRef, warnTextRef].forEach((r) => {
237-
if (r.current) {
238-
r.current.style.maxWidth = `${measuredWidth}px`;
239-
r.current.style.overflowWrap = 'break-word';
240-
}
235+
236+
if (!wrapperRef.current) return;
237+
const applyWidth = (width: number) => {
238+
[helperTextRef, errorTextRef, warnTextRef].forEach((r) => {
239+
if (r.current) {
240+
r.current.style.maxWidth = `${width}px`;
241+
r.current.style.overflowWrap = 'break-word';
242+
}
243+
});
244+
};
245+
246+
const resizeObserver = new ResizeObserver(([entry]) => {
247+
applyWidth(entry.contentRect.width);
241248
});
249+
resizeObserver.observe(wrapperRef.current);
250+
251+
return () => resizeObserver && resizeObserver.disconnect();
242252
}, [other.cols, invalid, warn]);
243253

244254
const textareaProps: {

packages/web-components/src/components/textarea/textarea.ts

Lines changed: 18 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -156,10 +156,10 @@ class CDSTextarea extends CDSTextInput {
156156
private _prevCounterMode: 'character' | 'word' = this.counterMode;
157157

158158
/**
159-
* The previous cols value. This lets updated() conditionally call _measureWrapper()
160-
* if the cols value has changed.
159+
* Observes the textarea wrapper’s size to re-measure helper/invalid/warn text width when
160+
* cols is updated
161161
*/
162-
private _prevCols?: number;
162+
private _resizeObserver?: ResizeObserver;
163163

164164
render() {
165165
const { enableCounter, maxCount } = this;
@@ -272,10 +272,6 @@ class CDSTextarea extends CDSTextInput {
272272
}
273273
updated(): void {
274274
super.updated?.();
275-
if (this.cols !== this._prevCols) {
276-
this._prevCols = this.cols;
277-
this._measureWrapper();
278-
}
279275
if (this.counterMode !== this._prevCounterMode) {
280276
const textarea = this._textarea;
281277
if (textarea) {
@@ -287,6 +283,16 @@ class CDSTextarea extends CDSTextInput {
287283
}
288284
this._prevCounterMode = this.counterMode;
289285
}
286+
287+
const wrapper = this.shadowRoot?.querySelector<HTMLElement>(
288+
`.${prefix}--text-area__wrapper`
289+
);
290+
if (!wrapper) return;
291+
292+
this._resizeObserver = new ResizeObserver(() => {
293+
this._measureWrapper();
294+
});
295+
this._resizeObserver.observe(wrapper);
290296
}
291297

292298
/**
@@ -314,6 +320,11 @@ class CDSTextarea extends CDSTextInput {
314320
});
315321
}
316322

323+
disconnectedCallback() {
324+
super.disconnectedCallback?.();
325+
this._resizeObserver?.disconnect();
326+
}
327+
317328
static shadowRootOptions = {
318329
...LitElement.shadowRootOptions,
319330
delegatesFocus: true,

0 commit comments

Comments
 (0)