Floating Window

Pro

A movable, resizable window over your app, the way a desktop keeps a second document at hand. Drag it by its title bar, resize it from the corner, double-click the bar to fold it away. Geometry is in rem, so it scales with the root font size, and the app keeps the state.

Installation#

# One-time setup (tokens + lib helpers)npx koalaui-cli@latest init# Activate your Pro license (once per machine)npx koalaui-cli@latest login <key># Add this component (its dependencies come along)npx koalaui-cli@latest add floating-window

Usage#

This example is part of Koala UI Pro

The preview is yours to explore. Its code comes with a Pro license, paid once and used in every project.

Have a license? Unlock it here

Anatomy#

import { FloatingWindow, FloatingWindowLayer } from "@/components/ui/floating-window"<FloatingWindowLayer>  <FloatingWindow title="…" x={…} y={…} width={…} height={…}>    …  </FloatingWindow></FloatingWindowLayer>

Managing windows#

The window is controlled: it reports a drag through onMove(x, y) and a resize through onResize(width, height), already kept inside the layer and above the minimum, and draws whatever you pass back. The z-order is yours too: give each window a zIndex and raise it in onFocusWindow, which fires when the window is pressed anywhere or focus moves into it from outside. A few lines of state are the whole window manager.

This example is part of Koala UI Pro

The preview is yours to explore. Its code comes with a Pro license, paid once and used in every project.

Have a license? Unlock it here

Minimize and controls#

minimized folds the window up to its title bar, like a window shade. Its content stays mounted (a half-written note survives) and turns inert until it unfolds. The bar shows a control only for a handler you pass: onToggleMinimize adds the minimize button and the double-click on the bar, onClose adds the close button. Double-click the folded bar below.

Sizing in rem#

x, y, width, height, minWidth (18 by default) and minHeight (4.25: the bar and 2rem of content) are all rem, so a UI that scales by changing the root font size scales its windows with it. The pointer is converted with the root font size read when a drag starts. A move keeps 6rem of the window inside the layer on the left (the controls) and 4rem on the right, and the bar never leaves the top or bottom; a resize stops half a rem short of the layer's far edges. Without a FloatingWindowLayer around it, a window is unbounded.

API reference#

FloatingWindowLayer

An absolute inset-0 <div> over its positioned parent, transparent to the pointer except where a window is. Its box bounds the windows inside it; a FloatingWindow outside a layer still works, without bounds. Every div prop is forwarded, ref included; className is merged last.

Data attributeDescription
data-slot"floating-window-layer".

FloatingWindow

A non-modal role="dialog" named by its title (or your aria-label). Controlled: it reports moves and resizes and the app keeps the state, z-order included. Every other div prop is forwarded; style merges over the geometry and className is merged last.

PropTypeDefaultDescription
title*React.ReactNode-The window's name: shown in the bar, and the dialog's accessible name.
iconReact.ElementType-A glyph before the title: the component, not an element (icon={Browser}).
x*number-Left edge inside the layer, in rem.
y*number-Top edge inside the layer, in rem.
width*number-Width in rem.
height*number-Height in rem, while not minimized.
minimizedbooleanfalseFolded to the title bar. The content stays mounted (and inert).
zIndexnumber-Stacking order among the layer's windows. Raise it in onFocusWindow.
minWidthnumber18Smallest width a resize can reach, in rem.
minHeightnumber4.25Smallest height a resize can reach, in rem: the bar and 2rem of content.
onFocusWindow() => void-The window was pressed, or focus moved into it: bring it to the front.
onMove(x: number, y: number) => void-A drag of the title bar: the new x and y, in rem, already kept inside the layer.
onResize(width: number, height: number) => void-A drag of the corner grip: the new width and height, in rem, within the limits.
onToggleMinimize() => void-Shows the minimize button and enables double-click on the bar.
onClose() => void-Shows the close button.
minimizeLabelstring"Minimize"The minimize button's accessible name.
closeLabelstring"Close"The close button's accessible name.
staticbooleanfalseKept for compatibility; controls no longer scale on press.
Data attributeDescription
data-slot"floating-window", with floating-window-bar, -title, -controls, -minimize, -close, -body and -grip inside.
data-state"open" or "minimized", on the window and on its body.
CSS variableDescription
--surfaceSet to var(--popover) on the body, the ground its controls paint on.

FAQ#

A Dialog interrupts: it is modal, centred and closes before you go on. A Floating Window sits beside the work, non-modal, so you can keep a record open while you use the page under it, and keep several.