Skip to content

Keep Web Chat's styles when a React 19.2 Activity hides and shows it - #6047

Merged
Eugene (OEvgeny) merged 6 commits into
mainfrom
OEvgeny/fix-activity-styles
Nov 13, 2026
Merged

Eugene (OEvgeny) merged 6 commits into
mainfrom
OEvgeny/fix-activity-styles

Conversation

@OEvgeny

@OEvgeny Eugene (OEvgeny) commented Nov 12, 2026 •

Copy link
Copy Markdown
Collaborator

Web Chat loses its styles when a React 19.2 <Activity> hides and shows it.

Changelog Entry

Fixed

  • Fixed styles lost after a React 19.2 <Activity> hides and shows Web Chat, in PR #6047, by @OEvgeny

Description

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

  • Rebuild from emotion's registered styles, not re-append the removed elements: production emotion uses insertRule(), whose rules are lost with the element, and classes created while hidden need rules too.
  • Effects cannot tell hiding from unmounting, so removal cannot wait for unmount. Not @emotion/react (never removes styles): CSS modules are replacing emotion.
  • Only mounted instances are shared: two Web Chats rendered in the same commit get two sheets.

Specific Changes

  • useEmotion.ts: count in a layout effect, re-insert the registered rules after the last release

  • react19/activity.hideShow{,.fluent,.styleOptions}.html: same look after hide and show (default, Fluent), style options changed while hidden

  • react19/strictMode.unmount.styles.html, strictMode/unmount.styles.html: unmount removes the styles

  • basic/twoWebChats.unmountOne.html: the other Web Chat keeps the shared styles

  • react19/activity.hideShow.sharedStyles.html: shown again, then the other unmounts: styles kept

  • I have added tests and executed them locally

  • I have added .changelog/<PR#>-<slug>.md

  • I have updated documentation

Review Checklist

This section is for contributors to review your work.

  • Accessibility reviewed (tab order, content readability, alt text, color contrast)
  • Browser and platform compatibilities reviewed
  • CSS styles reviewed (minimal rules, no z-index)
  • Documents reviewed (docs, samples, live demo)
  • Internationalization reviewed (strings, unit formatting)
  • package.json and package-lock.json reviewed
  • Security reviewed (no data URIs, check for nonce leak)
  • Tests reviewed (coverage, legitimacy)

Eugene Olonov added 5 commits November 12, 2026 11:43
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.

Copilot AI 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.

🔵 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

@compulim William Wong (compulim) left a comment •

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

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>.

@OEvgeny

Copy link
Copy Markdown
Collaborator Author

Thanks. Agreed on the general point: anything created in useMemo() and undone in an effect cleanup doesn't survive <StrictMode> or an <Activity> hide and show. I'll go through the other useMemo() and effect pairs and send fixes in small follow-ups, each with a React 19 test page.

@OEvgeny
Eugene (OEvgeny) merged commit 7697bdf into main Nov 13, 2026
46 checks passed
@OEvgeny
Eugene (OEvgeny) deleted the OEvgeny/fix-activity-styles branch November 13, 2026 00:31
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants