FloatingWindow

Use DragHandle when controls inside the window need their own pointer interactions. Without it, the whole surface can be dragged.

Basics

Drag the header to move the window. The corner grip resizes it.

Loading demo…

import { useState } from 'react'; import { Button, FloatingWindow, Text } from '@plocks/ui'; export function Demo() { const [opened, setOpened] = useState(false); return ( <> <Button onPress={() => setOpened((value) => !value)}> {opened ? 'Hide window' : 'Show window'} </Button> {opened && ( <FloatingWindow dimensions={{ initialWidth: 260, initialHeight: 160 }} initialPosition={{ top: 90, left: 40 }} p="md" > <FloatingWindow.DragHandle> <Text fw="600">Drag this header</Text> </FloatingWindow.DragHandle> <Text>Move or resize this window.</Text> <FloatingWindow.ResizeHandle /> </FloatingWindow> )} </> ); }

Without Viewport Constraint

constrainToViewport={false} lets the window move beyond the viewport edge.

Loading demo…

import { useState } from 'react'; import { Button, FloatingWindow, Text } from '@plocks/ui'; export function Demo() { const [opened, setOpened] = useState(false); return ( <> <Button onPress={() => setOpened(!opened)}>Toggle window</Button> {opened && ( <FloatingWindow w={240} p="md" constrainToViewport={false}> <Text>Drag beyond the viewport.</Text> </FloatingWindow> )} </> ); }

Drag Handle

The DragHandle confines movement to one region, leaving child buttons interactive.

Loading demo…

import { useState } from 'react'; import { Button, FloatingWindow, Text } from '@plocks/ui'; export function Demo() { const [opened, setOpened] = useState(false); return ( <> <Button onPress={() => setOpened(true)}>Open window</Button> {opened && ( <FloatingWindow w={260} p="md"> <FloatingWindow.DragHandle> <Text fw="600">Drag here</Text> </FloatingWindow.DragHandle> <Button size="sm" onPress={() => setOpened(false)}> Close </Button> </FloatingWindow> )} </> ); }

Disabled Dragging

enabled={false} keeps the window fixed in place.

Loading demo…

import { useState } from 'react'; import { Button, FloatingWindow, Text } from '@plocks/ui'; export function Demo() { const [opened, setOpened] = useState(false); return ( <> <Button onPress={() => setOpened(!opened)}>Toggle static window</Button> {opened && ( <FloatingWindow enabled={false} w={220} p="md"> <Text>This window stays put.</Text> </FloatingWindow> )} </> ); }

Constrain Offset

constrainOffset keeps space between the window and viewport edges.

Loading demo…

import { useState } from 'react'; import { Button, FloatingWindow, Text } from '@plocks/ui'; export function Demo() { const [opened, setOpened] = useState(false); return ( <> <Button onPress={() => setOpened(!opened)}>Toggle inset window</Button> {opened && ( <FloatingWindow constrainOffset={30} w={220} p="md"> <Text>30 px from the edge.</Text> </FloatingWindow> )} </> ); }

Lock Axis

axis="x" limits dragging to the horizontal axis.

Loading demo…

import { useState } from 'react'; import { Button, FloatingWindow, Text } from '@plocks/ui'; export function Demo() { const [opened, setOpened] = useState(false); return ( <> <Button onPress={() => setOpened(!opened)}>Toggle horizontal window</Button> {opened && ( <FloatingWindow axis="x" w={220} p="md"> <Text>Drag horizontally.</Text> </FloatingWindow> )} </> ); }

Set Position

setPositionRef can move the window to a new viewport inset.

Loading demo…

import { useRef, useState } from 'react'; import { Button, FloatingWindow, Text } from '@plocks/ui'; import type { FloatingWindowHandle } from '@plocks/ui'; export function Demo() { const [opened, setOpened] = useState(false); const windowRef = useRef<FloatingWindowHandle>(null); return ( <> <Button onPress={() => setOpened(true)}>Open window</Button> {opened && ( <FloatingWindow setPositionRef={windowRef} initialPosition={{ top: 100, left: 40 }} dimensions={{ initialWidth: 240, initialHeight: 140 }} p="md" > <FloatingWindow.DragHandle> <Text fw="600">Move me</Text> </FloatingWindow.DragHandle> <Button onPress={() => windowRef.current?.setPosition({ top: 60, right: 60 })}> Move to top right </Button> </FloatingWindow> )} </> ); }

Resize Handle

FloatingWindow.ResizeHandle resizes within the limits in dimensions.

Loading demo…

import { useState } from 'react'; import { Button, FloatingWindow, Text } from '@plocks/ui'; export function Demo() { const [opened, setOpened] = useState(false); return ( <> <Button onPress={() => setOpened(true)}>Open resizable window</Button> {opened && ( <FloatingWindow initialPosition={{ top: 110, left: 60 }} dimensions={{ initialWidth: 230, initialHeight: 130, minWidth: 160, minHeight: 90, maxWidth: 360, maxHeight: 280, }} p="md" > <FloatingWindow.DragHandle> <Text fw="600">Resizable window</Text> </FloatingWindow.DragHandle> <FloatingWindow.ResizeHandle /> </FloatingWindow> )} </> ); }

Resize Callbacks

onSizeChange reports the final window dimensions after a resize.

Loading demo…

import { useState } from 'react'; import { Button, FloatingWindow, Text } from '@plocks/ui'; export function Demo() { const [opened, setOpened] = useState(false); const [size, setSize] = useState({ width: 240, height: 140 }); return ( <> <Button onPress={() => setOpened(true)}>Open window</Button> {opened && ( <FloatingWindow initialPosition={{ top: 110, left: 60 }} dimensions={{ initialWidth: 240, initialHeight: 140 }} onSizeChange={setSize} p="md" > <FloatingWindow.DragHandle> <Text fw="600">Resize me</Text> </FloatingWindow.DragHandle> <Text> {Math.round(size.width)} × {Math.round(size.height)} </Text> <FloatingWindow.ResizeHandle /> </FloatingWindow> )} </> ); }
Scan to open this page on your phoneplocks.dev/ui/FloatingWindow