From cafe620e01106262b8876f1bb927189337523b75 Mon Sep 17 00:00:00 2001
From: oliver <97427849+flamboh@users.noreply.github.com>
Date: Sun, 11 Oct 2026 14:27:41 -0700
Subject: [PATCH] fix(desktop): tooltips no longer open under the Windows and
Linux window controls (#17672)
---
apps/web/src/components/ui/tooltip.tsx | 37 +++++++++++++++++------
apps/web/src/lib/windowControlsOverlay.ts | 19 ++++++++++++
2 files changed, 47 insertions(+), 9 deletions(-)
diff --git a/apps/web/src/components/ui/tooltip.tsx b/apps/web/src/components/ui/tooltip.tsx
index 1017a787931fd4233f5571c46b8842bd0fa9ee79..fbd338afbc16aece179578d7e6b8e82742f92193 100644
--- a/apps/web/src/components/ui/tooltip.tsx
+++ b/apps/web/src/components/ui/tooltip.tsx
@@ -2,6 +2,10 @@ import { Tooltip as TooltipPrimitive } from "@base-ui/react/tooltip";
import { createContext, use, useEffect, useRef, type ComponentProps, type RefObject } from "react";
import { cn } from "~/lib/utils";
+import { useNativeTitlebarHeight } from "~/lib/windowControlsOverlay";
+
+// Base UI's default, restated because a padding object zeroes the sides it omits.
+const COLLISION_PADDING = 5;
const TooltipProvider = TooltipPrimitive.Provider;
@@ -80,6 +84,28 @@ function TooltipTrigger(props: TooltipPrimitive.Trigger.Props) {
);
}
+/**
+ * Treats the native titlebar strip as off-screen, so a tooltip that would open
+ * under the window controls flips to its other side. Rendered inside the
+ * portal so only open tooltips track the titlebar.
+ */
+function TooltipPositioner(props: TooltipPrimitive.Positioner.Props) {
+ const titlebarHeight = useNativeTitlebarHeight();
+ return (
+
+ );
+}
+
function TooltipPopup({
className,
align = "center",
@@ -99,14 +125,7 @@ function TooltipPopup({
}) {
return (
-
+
-
+
);
}
diff --git a/apps/web/src/lib/windowControlsOverlay.ts b/apps/web/src/lib/windowControlsOverlay.ts
index 7c9e8e8553b3f12be35fc2a4ee4842ee9bd2b63b..6508ebc4a0edb9e125fa40949287ad07732fb989 100644
--- a/apps/web/src/lib/windowControlsOverlay.ts
+++ b/apps/web/src/lib/windowControlsOverlay.ts
@@ -1,3 +1,5 @@
+import { useSyncExternalStore } from "react";
+
import { isWindowsPlatform } from "./utils";
const WCO_CLASS_NAME = "wco";
@@ -6,6 +8,7 @@ const ELECTRON_WINDOWS_CLASS_NAME = "electron-windows";
interface WindowControlsOverlayLike {
readonly visible: boolean;
+ getTitlebarAreaRect(): DOMRect;
addEventListener(type: "geometrychange", listener: EventListener): void;
removeEventListener(type: "geometrychange", listener: EventListener): void;
}
@@ -43,6 +46,22 @@ export function syncDocumentWindowControlsOverlayClass(): () => void {
};
}
+function subscribeTitlebarArea(listener: () => void): () => void {
+ const overlay = getWindowControlsOverlay();
+ overlay?.addEventListener("geometrychange", listener);
+ return () => overlay?.removeEventListener("geometrychange", listener);
+}
+
+function getNativeTitlebarHeight(): number {
+ const overlay = getWindowControlsOverlay();
+ return overlay?.visible ? overlay.getTitlebarAreaRect().bottom : 0;
+}
+
+/** Height of the strip at the top of the window where native window controls paint over the page. */
+export function useNativeTitlebarHeight(): number {
+ return useSyncExternalStore(subscribeTitlebarArea, getNativeTitlebarHeight, () => 0);
+}
+
function getElectronPlatformClassNames(
platform: string,
):
--
2.54.0