Repository navigation
Keep Web Chat's styles when a React 19.2 Activity hides and shows it - #6047
Conversation
Also in Strict Mode on React 18 and 19, and when one of two Web Chats sharing styles unmounts.
useEmotion() counted references in useMemo(), during render. A hidden <Activity> runs the effect cleanup, which removed the style elements, and showing it runs the effect again without rendering, so nothing put them back. Count in a layout effect instead, and rebuild the rules from the registered styles when acquired after the last release.
… an Activity showed Web Chat again Drop the computed-style assertions. The new page fails when the reference count goes back into render.
There was a problem hiding this comment.
🔵 Needs a closer look
Emotion CSSOM restoration and cascade ordering require browser lifecycle validation, especially during Activity/Strict Mode replay and production insertRule use, which the review environment could not verify.
No open issues 🎉
What changed in this PR
Updates Web Chat’s Emotion stylesheet lifecycle to restore styles after React 19.2 <Activity> hide/show cycles while preserving shared styles and unmount cleanup.
Changes:
- Moves reference counting into a layout effect and restores registered CSS rules after cleanup.
- Adds regression tests for Activity visibility, hidden style-option updates, Fluent styling, shared styles, and Strict Mode cleanup.
- Adds a changelog entry for the fix.
| File | Description |
|---|---|
packages/component/src/hooks/internal/useEmotion.ts |
Tracks mounted consumers and restores Emotion rules during effect setup. |
.changelog/6047-fix-activity-styles.md |
Documents the Activity styling fix. |
__tests__/html2/strictMode/unmount.styles.html |
Checks React 18 Strict Mode styling and unmount cleanup. |
__tests__/html2/react19/strictMode.unmount.styles.html |
Checks React 19 Strict Mode styling and unmount cleanup. |
__tests__/html2/react19/activity.hideShow.styleOptions.html |
Checks that style-option changes made while hidden appear when shown. |
__tests__/html2/react19/activity.hideShow.sharedStyles.html |
Checks shared styles survive hide/show and another instance’s unmount. |
__tests__/html2/react19/activity.hideShow.html |
Checks default styling survives Activity hide/show. |
__tests__/html2/react19/activity.hideShow.fluent.html |
Checks Fluent styling survives Activity hide/show. |
__tests__/html2/basic/twoWebChats.unmountOne.html |
Checks the remaining Web Chat retains shared styles after another unmounts. |
Review effort: Balanced
There was a problem hiding this comment.
React 19.2 quirks: <StrictMode> will re-run effect (unmount/remount) without rendering. I.e. things in useMemo are not rerun.
In this scenario, we have useMemo writing new thing and useEffect delete it on unmount. Our useMemo will never trigger again in <StrictMode> initial render, that item is gone until subsequent render.
Asymmetricity use of useMemo and useXXXEffect may need to be revisited later. I.e. things that we did in useMemo and undo-ed in useXXXEffect need to revisit to make sure they survive <StrictMode>.
|
Thanks. Agreed on the general point: anything created in |
Changelog Entry
Fixed
<Activity>hides and shows Web Chat, in PR #6047, by @OEvgenyDescription
When a React 19.2
<Activity>hid Web Chat, the effect cleanup removed its emotion<style>elements; showing it did not add them back, as the reference count was taken in render.useEmotion()now counts in a layout effect and, after the last release, inserts the registered rules again.Design
insertRule(), whose rules are lost with the element, and classes created while hidden need rules too.@emotion/react(never removes styles): CSS modules are replacing emotion.Specific Changes
useEmotion.ts: count in a layout effect, re-insert the registered rules after the last releasereact19/activity.hideShow{,.fluent,.styleOptions}.html: same look after hide and show (default, Fluent), style options changed while hiddenreact19/strictMode.unmount.styles.html,strictMode/unmount.styles.html: unmount removes the stylesbasic/twoWebChats.unmountOne.html: the other Web Chat keeps the shared stylesreact19/activity.hideShow.sharedStyles.html: shown again, then the other unmounts: styles keptI have added tests and executed them locally
I have added
.changelog/<PR#>-<slug>.mdI have updated documentation
Review Checklist
z-index)package.jsonandpackage-lock.jsonreviewed