Skip to content
Kappa
Floating Panel
@dicehub/kappav0.4.2

Floating Panel

A draggable, resizable non-modal window for tools that must remain visible over an application workspace.

<script setup lang="ts">
import { FloatingPanel } from "@dicehub/kappa/components/floating-panel";
import { Button } from "@dicehub/kappa/components/button";
</script>

<template>
  <FloatingPanel.Root :default-size="{ width: 340, height: 250 }">
    <FloatingPanel.Trigger as-child>
      <Button variant="outline">Open run monitor</Button>
    </FloatingPanel.Trigger>
    <FloatingPanel.Positioner>
      <FloatingPanel.Content>
        <FloatingPanel.DragTrigger>
          <FloatingPanel.Header>
            <FloatingPanel.Title>Run monitor</FloatingPanel.Title>
            <FloatingPanel.Control>
              <FloatingPanel.StageTrigger stage="minimized" />
              <FloatingPanel.StageTrigger stage="maximized" />
              <FloatingPanel.StageTrigger stage="default" />
              <FloatingPanel.Close />
            </FloatingPanel.Control>
          </FloatingPanel.Header>
        </FloatingPanel.DragTrigger>
        <FloatingPanel.Body>Run details</FloatingPanel.Body>
        <FloatingPanel.ResizeTrigger axis="se" />
      </FloatingPanel.Content>
    </FloatingPanel.Positioner>
  </FloatingPanel.Root>
</template>

Open full example (new tab)

Installation

Floating Panel is included in Kappa. Ark UI owns movement, resizing, bounds, focus restoration, stages, and panel stacking. Kappa provides the compound Vue API, compact window treatment, safe defaults, and optional Teleport.

Barrel

import { FloatingPanel } from "@dicehub/kappa";

Granular

import {
  FloatingPanel,
  FloatingPanelBody,
  FloatingPanelClose,
  FloatingPanelContent,
  FloatingPanelControl,
  FloatingPanelDragTrigger,
  FloatingPanelHeader,
  FloatingPanelPositioner,
  FloatingPanelResizeTrigger,
  FloatingPanelStageTrigger,
  FloatingPanelTitle,
  FloatingPanelTrigger,
} from "@dicehub/kappa/components/floating-panel";

Usage

Use Floating Panel for tools that must stay visible while the page behind them remains interactive. Use Dialog when work must stop until the user responds, Drawer for an edge-attached surface, and Resizable for panels that remain part of the document layout.

  • The Kappa root keeps dragged windows within their boundary and closes on Escape by default.
  • Its minimum size is 240 × 160 pixels. Ark retains the initial 320 × 240 size when no size is supplied.
  • Content stays mounted after close unless unmountOnExit is enabled. Set persistRect to preserve geometry across reopen.
  • Place interactive header content in Control or add data-no-drag.

Composition

Typical part hierarchy
FloatingPanel.Root
├── FloatingPanel.Trigger
├── FloatingPanel.Positioner + Teleport
│   └── FloatingPanel.Content
│       ├── FloatingPanel.DragTrigger
│       │   └── FloatingPanel.Header
│       │       ├── FloatingPanel.Title
│       │       └── FloatingPanel.Control
│       │           ├── FloatingPanel.StageTrigger
│       │           └── FloatingPanel.Close
│       ├── FloatingPanel.Body
│       └── FloatingPanel.ResizeTrigger × edge/corner
└── FloatingPanel.Context (optional)

Positioner owns the optional Teleport. This differs from Dialog and Drawer, where Content also creates the positioner. Keep the default Teleport and fixed strategy for viewport or application-work-area bounds. Disable Teleport only when the integration provides a matching positioning and boundary coordinate space.

Ark does not expose a controlled stage model. Use StageTrigger, the context methods, and stageChange to observe minimize, maximize, and restore operations.

useFloatingPanel is the raw Ark hook. Set the Kappa root defaults explicitly when its machine is passed to RootProvider, as shown below.

<script setup lang="ts">
import { FloatingPanel, useFloatingPanel } from "@dicehub/kappa/components/floating-panel";

const panel = useFloatingPanel({
  id: "metrics-panel",
  allowOverflow: false,
  closeOnEscape: true,
  defaultSize: { width: 360, height: 240 },
  minSize: { width: 240, height: 160 },
});
</script>

<template>
  <FloatingPanel.RootProvider :value="panel">
    <!-- Compound parts -->
  </FloatingPanel.RootProvider>
</template>

Examples

Transform tool

A compact technical window with editable content and a persistent action footer.

<script setup lang="ts">
import { ref } from "vue";
import { FloatingPanel } from "@dicehub/kappa/components/floating-panel";
import { Button, Input, Label } from "@dicehub/kappa";

const offsetX = ref("0");
</script>

<template>
  <FloatingPanel.Root persist-rect>
    <FloatingPanel.Trigger>Open transform tool</FloatingPanel.Trigger>
    <FloatingPanel.Positioner>
      <FloatingPanel.Content>
        <FloatingPanel.DragTrigger>
          <FloatingPanel.Header>
            <FloatingPanel.Title>Transform geometry</FloatingPanel.Title>
            <FloatingPanel.Control>
              <FloatingPanel.StageTrigger stage="minimized" />
              <FloatingPanel.StageTrigger stage="maximized" />
              <FloatingPanel.StageTrigger stage="default" />
              <FloatingPanel.Close />
            </FloatingPanel.Control>
          </FloatingPanel.Header>
        </FloatingPanel.DragTrigger>
        <FloatingPanel.Body>
          <Label for="offset-x">Offset X</Label>
          <Input id="offset-x" v-model="offsetX" />
          <footer data-no-drag>
            <Button variant="primary">Apply transform</Button>
          </footer>
        </FloatingPanel.Body>
        <FloatingPanel.ResizeTrigger axis="e" />
        <FloatingPanel.ResizeTrigger axis="s" />
        <FloatingPanel.ResizeTrigger axis="se" />
      </FloatingPanel.Content>
    </FloatingPanel.Positioner>
  </FloatingPanel.Root>
</template>

Controlled geometry

Bind position and size when application state must observe or restore panel geometry.

56, 42 · 328 × 244
<script setup lang="ts">
import { ref } from "vue";
import { FloatingPanel } from "@dicehub/kappa/components/floating-panel";

const position = ref({ x: 56, y: 42 });
const size = ref({ width: 328, height: 244 });
</script>

<template>
  <FloatingPanel.Root v-model:position="position" v-model:size="size">
    <!-- Positioner, Content, header, body, and resize triggers -->
  </FloatingPanel.Root>
</template>

Window stages

Stage triggers minimize, maximize, and restore without adding a second window-state implementation.

<FloatingPanel.Control>
  <FloatingPanel.StageTrigger stage="minimized" />
  <FloatingPanel.StageTrigger stage="maximized" />
  <FloatingPanel.StageTrigger stage="default" />
  <FloatingPanel.Close />
</FloatingPanel.Control>

Multiple windows

Interaction raises a panel above its siblings while preserving the rest of the workspace.

<template>
  <FloatingPanel.Root default-open>
    <!-- Variables window -->
  </FloatingPanel.Root>
  <FloatingPanel.Root default-open>
    <!-- Probe chart window; interaction raises it above the first -->
  </FloatingPanel.Root>
</template>

Bounded workspace

Keep the default fixed strategy and constrain the panel to a stable application work area.

<script setup lang="ts">
import { ref } from "vue";
import { FloatingPanel } from "@dicehub/kappa/components/floating-panel";

const workArea = ref<HTMLElement>();
const getBoundaryEl = () => workArea.value ?? null;
</script>

<template>
  <main ref="workArea" class="work-area">
    <FloatingPanel.Root
      default-open
      :allow-overflow="false"
      :get-boundary-el="getBoundaryEl"
    >
      <FloatingPanel.Positioner>
        <!-- Content -->
      </FloatingPanel.Positioner>
    </FloatingPanel.Root>
  </main>
</template>

Without drag or resize

Disable gestures while retaining the non-modal window, focus, and close contracts.

<FloatingPanel.Root :draggable="false" :resizable="false">
  <FloatingPanel.Trigger>Open summary</FloatingPanel.Trigger>
  <FloatingPanel.Positioner>
    <FloatingPanel.Content>
      <FloatingPanel.Header>
        <FloatingPanel.Title>Read-only summary</FloatingPanel.Title>
        <FloatingPanel.Control><FloatingPanel.Close /></FloatingPanel.Control>
      </FloatingPanel.Header>
      <FloatingPanel.Body>Summary content</FloatingPanel.Body>
    </FloatingPanel.Content>
  </FloatingPanel.Positioner>
</FloatingPanel.Root>

Accessibility

  • Always render Title or provide an accessible name on Content.
  • Floating Panel is non-modal. It does not make the page inert or trap focus.
  • Content is the default focus target. Arrow keys move it when it has focus.
  • ResizeTrigger supports pointer input. Provide application controls that call setSize when keyboard resizing is required.
  • Stage and close controls include default accessible labels. Supply translated labels when the interface locale changes.
  • A nested Select or Popover should receive Escape before the containing panel.

Keyboard Support

KeyBehavior
Arrow keysMoves the panel when Content has focus.
EscapeCloses the active panel when closeOnEscape is enabled.
TabMoves through controls without trapping focus in the non-modal panel.

API Reference

FloatingPanel.Root

PropTypeDefaultDescription
open / defaultOpenbooleanfalseControlled or initial open state.
position / defaultPositionFloatingPanelPoint—Controlled or initial x/y position in pixels.
size / defaultSizeFloatingPanelSize320 × 240Controlled or initial width and height in pixels.
minSizeFloatingPanelSize240 × 160Smallest permitted panel geometry.
maxSizeFloatingPanelSize—Largest permitted panel geometry.
draggablebooleantrueEnables pointer dragging and content arrow-key movement.
resizablebooleantrueEnables pointer resize triggers and stage changes.
allowOverflowbooleanfalseAllows dragging beyond the boundary when true.
getBoundaryEl() => HTMLElement | nullviewportReturns the element that constrains geometry.
gridSizenumber1Movement and resize snap interval in pixels.
persistRectbooleanfalseRetains geometry after close and reopen.
closeOnEscapebooleantrueCloses the panel when Escape reaches it.
strategy"fixed" | "absolute""fixed"Uses viewport-fixed or containing-block absolute positioning.
disabledbooleanfalseDisables window interaction.

Parts

PartElementDescription
FloatingPanel.TriggerbuttonOpens the panel.
FloatingPanel.PositionerdivOwns geometry, stack order, and optional Teleport.
FloatingPanel.ContentdivNon-modal window surface and focus target.
FloatingPanel.DragTriggerdivPointer drag area, normally wrapped around Header.
FloatingPanel.HeaderdivCompact window title bar.
FloatingPanel.TitledivAccessible panel name.
FloatingPanel.ControldivHeader actions protected from drag gestures.
FloatingPanel.StageTriggerbuttonMinimizes, maximizes, or restores the panel.
FloatingPanel.ClosebuttonCloses the panel; alias of CloseTrigger.
FloatingPanel.BodydivScrollable panel content, hidden while minimized.
FloatingPanel.ResizeTriggerdivPointer resize edge or corner.
FloatingPanel.Context—Exposes the current Ark panel API to a slot.

Events

EventPayloadDescription
update:openbooleanUpdates controlled open state.
update:positionFloatingPanelPointUpdates controlled position during drag or movement.
update:sizeFloatingPanelSizeUpdates controlled size during resize.
openChangeFloatingPanelOpenChangeDetailsReports open-state details.
positionChange / positionChangeEndFloatingPanelPositionChangeDetailsReports live and committed position changes.
sizeChange / sizeChangeEndFloatingPanelSizeChangeDetailsReports live and committed size changes.
stageChangeFloatingPanelStageChangeDetailsReports minimize, maximize, or restore.

Exports

ExportDescription
FloatingPanelCompound component with all public parts.
FloatingPanelRootNamed root export.
useFloatingPanelCreates an Ark-owned panel machine for RootProvider.
useFloatingPanelContextReads panel state and imperative methods.
FloatingPanelPoint / FloatingPanelSizeControlled geometry types.
FloatingPanelStageThe default, minimized, or maximized stage union.