diff --git a/ui/app/(prowler)/lighthouse/_components/chat/message-bubble.test.tsx b/ui/app/(prowler)/lighthouse/_components/chat/message-bubble.test.tsx
index c63bdf3f08..8b6855392f 100644
--- a/ui/app/(prowler)/lighthouse/_components/chat/message-bubble.test.tsx
+++ b/ui/app/(prowler)/lighthouse/_components/chat/message-bubble.test.tsx
@@ -26,6 +26,21 @@ vi.mock("streamdown", () => ({
);
}
+ if (text.includes("graph TD")) {
+ // Mirrors streamdown's real mermaid DOM: pan/zoom wrapper + inline max-width on the svg
+ return (
+
+ );
+ }
+
return <>{children}>;
},
defaultRehypePlugins: { katex: undefined, harden: undefined },
@@ -87,6 +102,30 @@ describe("MessageBubble", () => {
"min-w-0",
);
});
+
+ it("keeps Mermaid diagrams inside the constrained markdown wrapper", () => {
+ // Given
+ const mermaidMessage = buildAssistantMessage([
+ textPart("part-1", "```mermaid\ngraph TD\n A --> B\n```"),
+ ]);
+
+ // When
+ render();
+
+ // Then
+ const mermaid = screen.getByRole("img", { name: "Mermaid chart" });
+ const markdown = mermaid.closest(".lighthouse-markdown");
+ if (!(markdown instanceof HTMLElement)) {
+ throw new Error("Expected markdown wrapper around Mermaid diagram");
+ }
+
+ expect(markdown).toHaveClass("min-w-0", "max-w-full", "overflow-x-auto");
+ expect(markdown.parentElement).toHaveClass("min-w-0");
+ expect(markdown.parentElement?.parentElement).toHaveClass(
+ "min-w-0",
+ "max-w-full",
+ );
+ });
});
function isBefore(first: HTMLElement, second: HTMLElement): boolean {
diff --git a/ui/styles/globals.css b/ui/styles/globals.css
index 6a902e6db1..a1f9b65dc9 100644
--- a/ui/styles/globals.css
+++ b/ui/styles/globals.css
@@ -317,6 +317,17 @@
min-width: 100%;
width: max-content;
}
+
+ .lighthouse-markdown [data-streamdown="mermaid-block"] {
+ max-width: 100%;
+ min-width: 0;
+ }
+
+ /* !important beats the inline max-width px that mermaid sets on the svg */
+ .lighthouse-markdown [data-streamdown="mermaid-block"] svg {
+ max-width: 100% !important;
+ height: auto;
+ }
}
/* ===== UTILITY LAYER ===== */