diff --git a/packages/ui/components/tooltip.wrn b/packages/ui/components/tooltip.wrn index 2c2f895e..8e980ad6 100644 --- a/packages/ui/components/tooltip.wrn +++ b/packages/ui/components/tooltip.wrn @@ -189,6 +189,12 @@ id: string = "" pointer-events: none; } + /* Closed until hovered or focused, including in server HTML before the + client applies data-show; otherwise every tooltip flashes on load. */ + .wrn-tooltip[data-open="false"] .wrn-tooltip__content { + display: none; + } + .wrn-tooltip[data-interactive="true"] .wrn-tooltip__content { pointer-events: auto; } diff --git a/packages/ui/test/tooltip-closed.test.ts b/packages/ui/test/tooltip-closed.test.ts new file mode 100644 index 00000000..cbb4f0e9 --- /dev/null +++ b/packages/ui/test/tooltip-closed.test.ts @@ -0,0 +1,8 @@ +import { expect, test } from "bun:test"; + +// Server HTML renders tooltip content before the client applies data-show, so +// a closed tooltip must also be hidden by CSS or it flashes on every page load. +test("closed tooltip content is hidden by CSS before hydration", async () => { + const source = await Bun.file(new URL("../components/tooltip.wrn", import.meta.url)).text(); + expect(source).toMatch(/\.wrn-tooltip\[data-open="false"\] \.wrn-tooltip__content \{\s*display: none;/); +});