From a850d187674d49f1d00a22cbc69ebc49aba3a4f3 Mon Sep 17 00:00:00 2001 From: PK Date: Tue, 30 Jun 2026 22:10:49 +0530 Subject: [PATCH] fix: guard Chatwoot bubble toggle until holder is in the DOM (#485) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ChatwootWidget's visibility effect took the synchronous fast path whenever `window.$chatwoot` was truthy. But the SDK assigns `$chatwoot` (with `toggleBubbleVisibility`) synchronously in run(), while `.woot--bubble-holder` is only appended later, after the widget iframe finishes loading. Calling `toggleBubbleVisibility("show")` in that gap makes the SDK dereference `null.classList` — an intermittent crash on navigating to /workflow that surfaces via the React error boundary (follow-up to #483). Gate the immediate-apply path on the bubble holder actually being in the DOM; when it's absent, fall through to the existing `chatwoot:ready` listener, which the SDK fires only after the holder is created. Co-authored-by: Claude Opus 4.8 (1M context) --- ui/src/components/ChatwootWidget.tsx | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/ui/src/components/ChatwootWidget.tsx b/ui/src/components/ChatwootWidget.tsx index 7872e666..9fe3e091 100644 --- a/ui/src/components/ChatwootWidget.tsx +++ b/ui/src/components/ChatwootWidget.tsx @@ -99,9 +99,12 @@ export default function ChatwootWidget() { } }; - // The SDK may not be ready on first navigation; apply once it fires - // `chatwoot:ready`, otherwise apply immediately. - if (window.$chatwoot) { + // Apply immediately only once the bubble holder is actually in the DOM. + // `window.$chatwoot` exists synchronously after run(), but `.woot--bubble-holder` + // is appended later when the widget iframe loads, and toggleBubbleVisibility() + // dereferences it with no null check. When it's absent, fall through to + // `chatwoot:ready`, which the SDK fires once the holder exists. + if (window.$chatwoot && document.querySelector(".woot--bubble-holder")) { applyVisibility(); return; }