diff --git a/src/canvas-host/server.test.ts b/src/canvas-host/server.test.ts
index 6a7cb82c990..ec95a74e731 100644
--- a/src/canvas-host/server.test.ts
+++ b/src/canvas-host/server.test.ts
@@ -145,6 +145,8 @@ describe("canvas host", () => {
expect(html).toContain("Interactive test page");
expect(html).toContain("openclawSendUserAction");
expect(html).toContain(CANVAS_WS_PATH);
+ expect(html).toContain('document.createElement("span")');
+ expect(html).not.toContain("statusEl.innerHTML");
} finally {
await server.close();
}
diff --git a/src/canvas-host/server.ts b/src/canvas-host/server.ts
index a42c7c5d6cd..6b582c8f100 100644
--- a/src/canvas-host/server.ts
+++ b/src/canvas-host/server.ts
@@ -121,11 +121,18 @@ function defaultIndexHTML() {
typeof window.openclawCanvasA2UIAction.postMessage === "function")
);
const hasHelper = () => typeof window.openclawSendUserAction === "function";
- statusEl.innerHTML =
- "Bridge: " +
- (hasHelper() ? "ready" : "missing") +
- " · iOS=" + (hasIOS() ? "yes" : "no") +
- " · Android=" + (hasAndroid() ? "yes" : "no");
+ const helperReady = hasHelper();
+ statusEl.textContent = "";
+ statusEl.appendChild(document.createTextNode("Bridge: "));
+ const bridgeStatus = document.createElement("span");
+ bridgeStatus.className = helperReady ? "ok" : "bad";
+ bridgeStatus.textContent = helperReady ? "ready" : "missing";
+ statusEl.appendChild(bridgeStatus);
+ statusEl.appendChild(
+ document.createTextNode(
+ " · iOS=" + (hasIOS() ? "yes" : "no") + " · Android=" + (hasAndroid() ? "yes" : "no"),
+ ),
+ );
const onStatus = (ev) => {
const d = ev && ev.detail || {};