Skip to content

Window snapping

Drag a window’s title bar toward the edge of the desktop. As the pointer crosses the activation threshold a translucent rectangle in the theme accent shows you the snap target. Release and the window snaps to that rectangle. It is the same gesture Windows Snap and macOS edge-drag use, in one consistent vocabulary.

Drag the Hello window toward the left edge to see the snap preview Open in new tab ↗
Pointer positionSnap target
Top edgeMaximize (fills the entire work area)
Left edgeLeft half
Right edgeRight half
Top-left cornerTop-left quarter
Top-right cornerTop-right quarter
Bottom-left cornerBottom-left quarter
Bottom-right cornerBottom-right quarter

Edge activation kicks in within 24 px of the edge. Corners take precedence when the pointer is within 48 px of both an edge pair.

ShortcutEffect
Cmd/Ctrl + ←Snap focused window to the left half
Cmd/Ctrl + →Snap focused window to the right half
Cmd/Ctrl + ↑Maximize (when not already)
Cmd/Ctrl + ↓Restore from maximize
Cmd/Ctrl + Shift + ←Top-left quarter
Cmd/Ctrl + Shift + →Top-right quarter
EscapeRestore from maximize

Every binding bails when the event target is a text input or contenteditable element, so typing in a field is never hijacked.

During a drag, Window.tsx reads the pointer position on every move event and asks computeSnapZone(x, y, work) whether the pointer is inside an activation threshold. If yes, it writes the resolved rectangle into a module-level snap-store. The <SnapPreview> overlay subscribes to that store and paints a translucent rectangle in the indicated zone. On pointerup the Window reads the current snap state. If a zone is active, the new bounds are the snap rect; otherwise the dragged position commits.

The store is intentionally module-scoped (same as notifications and the context menu) so the drag handler in Window and the preview rendered inside <Desktop> do not need to share a provider beyond the existing DesktopProvider.

If you build your own draggable surface (a floating tool panel, say), the snap math is exposed for you:

import {
computeSnapZone,
rectForZone,
setSnapPreview,
getSnapPreview,
} from "@react-ui-os/desktop";
function onPointerMove(e: PointerEvent) {
const work = /* your work area */;
const zone = computeSnapZone(e.clientX, e.clientY, work);
setSnapPreview(
zone
? { windowId: "my-panel", zone, rect: rectForZone(zone, work) }
: null,
);
}
function onPointerUp() {
const snap = getSnapPreview();
if (snap?.windowId === "my-panel") {
applyRect(snap.rect);
}
setSnapPreview(null);
}
  • Snap preview is aria-hidden: it is a visual hint, not a status.
  • Keyboard shortcuts work without any pointer interaction.
  • Reduced-motion preferences keep the preview’s slide transition short. The window snap itself is instantaneous either way.