Skip to content

fix(macos): make window draggable via data-tauri-drag-region - #29

Open
AranyiRaz wants to merge 1 commit into
vnknowledge2014:mainfrom
AranyiRaz:fix/macos-window-drag
Open

fix(macos): make window draggable via data-tauri-drag-region#29
AranyiRaz wants to merge 1 commit into
vnknowledge2014:mainfrom
AranyiRaz:fix/macos-window-drag

Conversation

@AranyiRaz

Copy link
Copy Markdown

Problem

On macOS the window cannot be moved with the mouse — there is no draggable surface anywhere.

Two things combine to cause it:

  1. No native title bar to drag. tauri.conf.json sets "titleBarStyle": "Overlay" + "hiddenTitle": true. Overlay mode removes the native draggable title bar and leaves only floating traffic lights over the webview, making the app responsible for supplying its own drag region.

  2. The drag region was written for the wrong framework. The only drag mechanism in the codebase was -webkit-app-region: drag — an Electron-only, non-standard CSS property. WKWebView (which Tauri uses on macOS) does not implement it; it parses and is silently ignored. Tauri's actual mechanism, the data-tauri-drag-region attribute, appeared zero times in the repo.

The intent was already there: .tauri-app .sidebar-header and .tauri-app .content-header add padding-top: 40px specifically to clear the traffic lights. The headers were designed as a custom title bar — only the drag mechanism targeted Electron's API instead of Tauri's.

Fix

  • src/App.tsx — one persistent empty 40px drag strip at the top of app-layout, rendered only under Tauri via the existing module-level isTauri const.
  • src/index.css.titlebar-drag style; removed the three inert -webkit-app-region declarations.
  • src-tauri/capabilities/default.json — granted core:window:allow-start-dragging.

No page components touched.

Why a dedicated element instead of tagging the headers

The injected handler at the pinned tauri version (2.10.3, crates/tauri/src/window/scripts/drag.js) reads the attribute off e.target only:

const attr = e.target.getAttribute(TAURI_DRAG_REGION_ATTR)

No ancestor walk. Putting the attribute on .content-header would make only the header's own padding draggable — mousedown on the <h1> or subtitle <span> sets e.target to that child, which has no attribute, so most of the visible header would stay dead. (tauri's dev branch has since gained ancestor-walking and a "deep" value, but neither exists in 2.10.3.)

A persistent strip also avoids dead zones: .content-header is rendered independently by each page and unmounted on every page switch, and two states render no header at all — Dashboard's loading branch and the Suspense fallback for lazy pages. A header-based region would intermittently not exist.

Why the permission is required

core:window:default at tag tauri-v2.10.3 lists 27 permissions and allow-start-dragging is not among them, while the capability file granted no core:window:* permission at all. Without the explicit grant, plugin:window|start_dragging is rejected at the ACL layer and dragging silently fails even with the attribute wired correctly.

allow-internal-toggle-maximize is in the default set, so double-click-to-zoom needs nothing extra.

Z-index

The strip sits at z-index: 50, deliberately below every blocking overlay so modal semantics are preserved (.modal-overlay 100, .ctx-overlay 200, .tour-backdrop 901, .wizard-overlay 1000). It carries no background (headers show through) and no pointer-events: none (it must receive mousedown).

Testing

Verified manually on macOS with npm run tauri dev: window drags, double-click zooms/restores, traffic lights still respond, headers remain fully interactive, modals still block dragging, and no dead zone during loading states.

Also passing: npx tsc --noEmit, npm run build, and grep -rn "webkit-app-region" src/ returns nothing.

No automated test accompanies this — the repo has no test infrastructure, and the behaviour is native window dragging that can only be confirmed on macOS hardware.

Out of scope

Not extracting a shared <PageHeader>. The 17 .content-header occurrences deviate substantially (Kubernetes' subtitle is a StatusDot + text node; LinuxVMs uses different title text between its two occurrences; several action wrappers carry inline styles), so that refactor is unrelated to this bug and worth a separate issue.

The window used titleBarStyle "Overlay" (no native draggable title bar)
while the only drag mechanism in the app was -webkit-app-region, an
Electron-only CSS property that WKWebView parses and silently ignores.
Result: no draggable surface anywhere on macOS.

Add a persistent 40px drag strip at the top of the window, rendered only
under Tauri, covering the band both headers already reserve as empty
padding for the traffic lights. Grant core:window:allow-start-dragging,
which is not part of core:window:default and so was rejected at the ACL
layer. Remove the three inert -webkit-app-region declarations.

The strip is a dedicated empty element rather than an attribute on the
headers because tauri 2.10.3's injected handler matches the attribute on
e.target only, with no ancestor walk -- tagging a header would leave its
title and subtitle children undraggable. A persistent strip also avoids
dead zones during the loading and Suspense states, which render no
header at all.

z-index 50 keeps it below every blocking overlay so modal semantics are
preserved.
@AranyiRaz

Copy link
Copy Markdown
Author

@architectureman

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants