Floating Panel
Used to display content in a non-modal floating window.
Anatomy
To set up the editable correctly, you'll need to understand its anatomy and how we name its parts.
Each part includes a
data-partattribute to help identify them in the DOM.
Examples
Learn how to use the FloatingPanel component in your project. Let's take a look at the most basic example:
import { FloatingPanel } from '@ark-ui/react/floating-panel'
import { Portal } from '@ark-ui/react/portal'
import { ArrowDownLeft, Maximize2, Minus, XIcon } from 'lucide-react'
export const Basic = () => (
<FloatingPanel.Root>
<FloatingPanel.Trigger>Toggle Panel</FloatingPanel.Trigger>
<Portal>
<FloatingPanel.Positioner>
<FloatingPanel.Content>
<FloatingPanel.DragTrigger>
<FloatingPanel.Header>
<FloatingPanel.Title>Floating Panel</FloatingPanel.Title>
<FloatingPanel.Control>
<FloatingPanel.StageTrigger stage="minimized">
<Minus />
</FloatingPanel.StageTrigger>
<FloatingPanel.StageTrigger stage="maximized">
<Maximize2 />
</FloatingPanel.StageTrigger>
<FloatingPanel.StageTrigger stage="default">
<ArrowDownLeft />
</FloatingPanel.StageTrigger>
<FloatingPanel.CloseTrigger>
<XIcon />
</FloatingPanel.CloseTrigger>
</FloatingPanel.Control>
</FloatingPanel.Header>
</FloatingPanel.DragTrigger>
<FloatingPanel.Body>
<p>Some content</p>
</FloatingPanel.Body>
<FloatingPanel.ResizeTrigger axis="n" />
<FloatingPanel.ResizeTrigger axis="e" />
<FloatingPanel.ResizeTrigger axis="w" />
<FloatingPanel.ResizeTrigger axis="s" />
<FloatingPanel.ResizeTrigger axis="ne" />
<FloatingPanel.ResizeTrigger axis="se" />
<FloatingPanel.ResizeTrigger axis="sw" />
<FloatingPanel.ResizeTrigger axis="nw" />
</FloatingPanel.Content>
</FloatingPanel.Positioner>
</Portal>
</FloatingPanel.Root>
)
import { FloatingPanel } from '@ark-ui/solid/floating-panel'
import { ArrowDownLeft, Maximize2, Minus, XIcon } from 'lucide-solid'
import { Portal } from 'solid-js/web'
export const Basic = () => (
<FloatingPanel.Root>
<FloatingPanel.Trigger>Toggle Panel</FloatingPanel.Trigger>
<Portal>
<FloatingPanel.Positioner>
<FloatingPanel.Content>
<FloatingPanel.DragTrigger>
<FloatingPanel.Header>
<FloatingPanel.Title>Floating Panel</FloatingPanel.Title>
<FloatingPanel.Control>
<FloatingPanel.StageTrigger stage="minimized">
<Minus />
</FloatingPanel.StageTrigger>
<FloatingPanel.StageTrigger stage="maximized">
<Maximize2 />
</FloatingPanel.StageTrigger>
<FloatingPanel.StageTrigger stage="default">
<ArrowDownLeft />
</FloatingPanel.StageTrigger>
<FloatingPanel.CloseTrigger>
<XIcon />
</FloatingPanel.CloseTrigger>
</FloatingPanel.Control>
</FloatingPanel.Header>
</FloatingPanel.DragTrigger>
<FloatingPanel.Body>
<p>Some content</p>
</FloatingPanel.Body>
<FloatingPanel.ResizeTrigger axis="n" />
<FloatingPanel.ResizeTrigger axis="e" />
<FloatingPanel.ResizeTrigger axis="w" />
<FloatingPanel.ResizeTrigger axis="s" />
<FloatingPanel.ResizeTrigger axis="ne" />
<FloatingPanel.ResizeTrigger axis="se" />
<FloatingPanel.ResizeTrigger axis="sw" />
<FloatingPanel.ResizeTrigger axis="nw" />
</FloatingPanel.Content>
</FloatingPanel.Positioner>
</Portal>
</FloatingPanel.Root>
)
<script setup lang="ts">
import { FloatingPanel } from '@ark-ui/vue/floating-panel'
import { ArrowDownLeft, Maximize2, Minus, XIcon } from 'lucide-vue-next'
</script>
<template>
<FloatingPanel.Root>
<FloatingPanel.Trigger>Toggle Panel</FloatingPanel.Trigger>
<Teleport to="body">
<FloatingPanel.Positioner>
<FloatingPanel.Content>
<FloatingPanel.DragTrigger>
<FloatingPanel.Header>
<FloatingPanel.Title>Floating Panel</FloatingPanel.Title>
<FloatingPanel.Control>
<FloatingPanel.StageTrigger stage="minimized">
<Minus />
</FloatingPanel.StageTrigger>
<FloatingPanel.StageTrigger stage="maximized">
<Maximize2 />
</FloatingPanel.StageTrigger>
<FloatingPanel.StageTrigger stage="default">
<ArrowDownLeft />
</FloatingPanel.StageTrigger>
<FloatingPanel.CloseTrigger>
<XIcon />
</FloatingPanel.CloseTrigger>
</FloatingPanel.Control>
</FloatingPanel.Header>
</FloatingPanel.DragTrigger>
<FloatingPanel.Body>
<p>Some content</p>
</FloatingPanel.Body>
<FloatingPanel.ResizeTrigger axis="n" />
<FloatingPanel.ResizeTrigger axis="e" />
<FloatingPanel.ResizeTrigger axis="w" />
<FloatingPanel.ResizeTrigger axis="s" />
<FloatingPanel.ResizeTrigger axis="ne" />
<FloatingPanel.ResizeTrigger axis="se" />
<FloatingPanel.ResizeTrigger axis="sw" />
<FloatingPanel.ResizeTrigger axis="nw" />
</FloatingPanel.Content>
</FloatingPanel.Positioner>
</Teleport>
</FloatingPanel.Root>
</template>
<script lang="ts">
import { FloatingPanel } from '@ark-ui/svelte/floating-panel'
import { Portal } from '@ark-ui/svelte/portal'
</script>
<FloatingPanel.Root>
<FloatingPanel.Trigger>Toggle Panel</FloatingPanel.Trigger>
<Portal>
<FloatingPanel.Positioner>
<FloatingPanel.Content>
<FloatingPanel.DragTrigger>
<FloatingPanel.Header>
<FloatingPanel.Title>Floating Panel</FloatingPanel.Title>
<FloatingPanel.Control>
<FloatingPanel.StageTrigger stage="minimized">
<span>−</span>
</FloatingPanel.StageTrigger>
<FloatingPanel.StageTrigger stage="maximized">
<span>□</span>
</FloatingPanel.StageTrigger>
<FloatingPanel.StageTrigger stage="default">
<span>↗</span>
</FloatingPanel.StageTrigger>
<FloatingPanel.CloseTrigger>
<span>×</span>
</FloatingPanel.CloseTrigger>
</FloatingPanel.Control>
</FloatingPanel.Header>
</FloatingPanel.DragTrigger>
<FloatingPanel.Body>
<p>Some content</p>
</FloatingPanel.Body>
<FloatingPanel.ResizeTrigger axis="n" />
<FloatingPanel.ResizeTrigger axis="e" />
<FloatingPanel.ResizeTrigger axis="w" />
<FloatingPanel.ResizeTrigger axis="s" />
<FloatingPanel.ResizeTrigger axis="ne" />
<FloatingPanel.ResizeTrigger axis="se" />
<FloatingPanel.ResizeTrigger axis="sw" />
<FloatingPanel.ResizeTrigger axis="nw" />
</FloatingPanel.Content>
</FloatingPanel.Positioner>
</Portal>
</FloatingPanel.Root>
Controlling the size
To control the size of the floating panel programmatically, you can pass the size onResize prop to the machine.
import { FloatingPanel } from '@ark-ui/react/floating-panel'
import { Portal } from '@ark-ui/react/portal'
import { ArrowDownLeft, Maximize2, Minus, XIcon } from 'lucide-react'
import { useState } from 'react'
export const ControlledSize = () => {
const [size, setSize] = useState({ width: 400, height: 300 })
return (
<FloatingPanel.Root size={size} onSizeChange={(e) => setSize(e.size)}>
<FloatingPanel.Trigger>Toggle Panel</FloatingPanel.Trigger>
<Portal>
<FloatingPanel.Positioner>
<FloatingPanel.Content>
<FloatingPanel.DragTrigger>
<FloatingPanel.Header>
<FloatingPanel.Title>Floating Panel</FloatingPanel.Title>
<FloatingPanel.Control>
<FloatingPanel.StageTrigger stage="minimized">
<Minus />
</FloatingPanel.StageTrigger>
<FloatingPanel.StageTrigger stage="maximized">
<Maximize2 />
</FloatingPanel.StageTrigger>
<FloatingPanel.StageTrigger stage="default">
<ArrowDownLeft />
</FloatingPanel.StageTrigger>
<FloatingPanel.CloseTrigger>
<XIcon />
</FloatingPanel.CloseTrigger>
</FloatingPanel.Control>
</FloatingPanel.Header>
</FloatingPanel.DragTrigger>
<FloatingPanel.Body>
<p>Some content</p>
</FloatingPanel.Body>
<FloatingPanel.ResizeTrigger axis="n" />
<FloatingPanel.ResizeTrigger axis="e" />
<FloatingPanel.ResizeTrigger axis="w" />
<FloatingPanel.ResizeTrigger axis="s" />
<FloatingPanel.ResizeTrigger axis="ne" />
<FloatingPanel.ResizeTrigger axis="se" />
<FloatingPanel.ResizeTrigger axis="sw" />
<FloatingPanel.ResizeTrigger axis="nw" />
</FloatingPanel.Content>
</FloatingPanel.Positioner>
</Portal>
</FloatingPanel.Root>
)
}
import { FloatingPanel } from '@ark-ui/solid/floating-panel'
import { ArrowDownLeft, Maximize2, Minus, XIcon } from 'lucide-solid'
import { createSignal } from 'solid-js'
import { Portal } from 'solid-js/web'
export const ControlledSize = () => {
const [size, setSize] = createSignal({ width: 400, height: 300 })
return (
<FloatingPanel.Root size={size()} onSizeChange={(e) => setSize(e.size)}>
<FloatingPanel.Trigger>Toggle Panel</FloatingPanel.Trigger>
<Portal>
<FloatingPanel.Positioner>
<FloatingPanel.Content>
<FloatingPanel.DragTrigger>
<FloatingPanel.Header>
<FloatingPanel.Title>Floating Panel</FloatingPanel.Title>
<FloatingPanel.Control>
<FloatingPanel.StageTrigger stage="minimized">
<Minus />
</FloatingPanel.StageTrigger>
<FloatingPanel.StageTrigger stage="maximized">
<Maximize2 />
</FloatingPanel.StageTrigger>
<FloatingPanel.StageTrigger stage="default">
<ArrowDownLeft />
</FloatingPanel.StageTrigger>
<FloatingPanel.CloseTrigger>
<XIcon />
</FloatingPanel.CloseTrigger>
</FloatingPanel.Control>
</FloatingPanel.Header>
</FloatingPanel.DragTrigger>
<FloatingPanel.Body>
<p>Some content</p>
</FloatingPanel.Body>
<FloatingPanel.ResizeTrigger axis="n" />
<FloatingPanel.ResizeTrigger axis="e" />
<FloatingPanel.ResizeTrigger axis="w" />
<FloatingPanel.ResizeTrigger axis="s" />
<FloatingPanel.ResizeTrigger axis="ne" />
<FloatingPanel.ResizeTrigger axis="se" />
<FloatingPanel.ResizeTrigger axis="sw" />
<FloatingPanel.ResizeTrigger axis="nw" />
</FloatingPanel.Content>
</FloatingPanel.Positioner>
</Portal>
</FloatingPanel.Root>
)
}
<script setup lang="ts">
import { FloatingPanel } from '@ark-ui/vue/floating-panel'
import { ArrowDownLeft, Maximize2, Minus, XIcon } from 'lucide-vue-next'
import { ref } from 'vue'
const size = ref({ width: 400, height: 300 })
</script>
<template>
<FloatingPanel.Root v-model:size="size">
<FloatingPanel.Trigger>Toggle Panel</FloatingPanel.Trigger>
<Teleport to="body">
<FloatingPanel.Positioner>
<FloatingPanel.Content>
<FloatingPanel.DragTrigger>
<FloatingPanel.Header>
<FloatingPanel.Title>Floating Panel</FloatingPanel.Title>
<FloatingPanel.Control>
<FloatingPanel.StageTrigger stage="minimized">
<Minus />
</FloatingPanel.StageTrigger>
<FloatingPanel.StageTrigger stage="maximized">
<Maximize2 />
</FloatingPanel.StageTrigger>
<FloatingPanel.StageTrigger stage="default">
<ArrowDownLeft />
</FloatingPanel.StageTrigger>
<FloatingPanel.CloseTrigger>
<XIcon />
</FloatingPanel.CloseTrigger>
</FloatingPanel.Control>
</FloatingPanel.Header>
</FloatingPanel.DragTrigger>
<FloatingPanel.Body>
<p>Some content</p>
</FloatingPanel.Body>
<FloatingPanel.ResizeTrigger axis="n" />
<FloatingPanel.ResizeTrigger axis="e" />
<FloatingPanel.ResizeTrigger axis="w" />
<FloatingPanel.ResizeTrigger axis="s" />
<FloatingPanel.ResizeTrigger axis="ne" />
<FloatingPanel.ResizeTrigger axis="se" />
<FloatingPanel.ResizeTrigger axis="sw" />
<FloatingPanel.ResizeTrigger axis="nw" />
</FloatingPanel.Content>
</FloatingPanel.Positioner>
</Teleport>
</FloatingPanel.Root>
</template>
<script lang="ts">
import { FloatingPanel } from '@ark-ui/svelte/floating-panel'
import { Portal } from '@ark-ui/svelte/portal'
import { ArrowDownLeft, Maximize2, Minus, XIcon } from 'lucide-svelte'
let size = $state({ width: 400, height: 300 })
</script>
<FloatingPanel.Root bind:size>
<FloatingPanel.Trigger>Toggle Panel</FloatingPanel.Trigger>
<Portal>
<FloatingPanel.Positioner>
<FloatingPanel.Content>
<FloatingPanel.DragTrigger>
<FloatingPanel.Header>
<FloatingPanel.Title>Floating Panel</FloatingPanel.Title>
<FloatingPanel.Control>
<FloatingPanel.StageTrigger stage="minimized">
<Minus />
</FloatingPanel.StageTrigger>
<FloatingPanel.StageTrigger stage="maximized">
<Maximize2 />
</FloatingPanel.StageTrigger>
<FloatingPanel.StageTrigger stage="default">
<ArrowDownLeft />
</FloatingPanel.StageTrigger>
<FloatingPanel.CloseTrigger>
<XIcon />
</FloatingPanel.CloseTrigger>
</FloatingPanel.Control>
</FloatingPanel.Header>
</FloatingPanel.DragTrigger>
<FloatingPanel.Body>
<p>Some content</p>
</FloatingPanel.Body>
<FloatingPanel.ResizeTrigger axis="n" />
<FloatingPanel.ResizeTrigger axis="e" />
<FloatingPanel.ResizeTrigger axis="w" />
<FloatingPanel.ResizeTrigger axis="s" />
<FloatingPanel.ResizeTrigger axis="ne" />
<FloatingPanel.ResizeTrigger axis="se" />
<FloatingPanel.ResizeTrigger axis="sw" />
<FloatingPanel.ResizeTrigger axis="nw" />
</FloatingPanel.Content>
</FloatingPanel.Positioner>
</Portal>
</FloatingPanel.Root>
Controlling the position
To control the position of the floating panel programmatically, you can pass the position and onPositionChange prop
to the machine.
import { FloatingPanel } from '@ark-ui/react/floating-panel'
import { Portal } from '@ark-ui/react/portal'
import { ArrowDownLeft, Maximize2, Minus, XIcon } from 'lucide-react'
import { useState } from 'react'
export const ControlledPosition = () => {
const [position, setPosition] = useState({ x: 200, y: 200 })
return (
<FloatingPanel.Root position={position} onPositionChange={(e) => setPosition(e.position)}>
<FloatingPanel.Trigger>Toggle Panel</FloatingPanel.Trigger>
<Portal>
<FloatingPanel.Positioner>
<FloatingPanel.Content>
<FloatingPanel.DragTrigger>
<FloatingPanel.Header>
<FloatingPanel.Title>Floating Panel</FloatingPanel.Title>
<FloatingPanel.Control>
<FloatingPanel.StageTrigger stage="minimized">
<Minus />
</FloatingPanel.StageTrigger>
<FloatingPanel.StageTrigger stage="maximized">
<Maximize2 />
</FloatingPanel.StageTrigger>
<FloatingPanel.StageTrigger stage="default">
<ArrowDownLeft />
</FloatingPanel.StageTrigger>
<FloatingPanel.CloseTrigger>
<XIcon />
</FloatingPanel.CloseTrigger>
</FloatingPanel.Control>
</FloatingPanel.Header>
</FloatingPanel.DragTrigger>
<FloatingPanel.Body>
<p>Some content</p>
</FloatingPanel.Body>
<FloatingPanel.ResizeTrigger axis="n" />
<FloatingPanel.ResizeTrigger axis="e" />
<FloatingPanel.ResizeTrigger axis="w" />
<FloatingPanel.ResizeTrigger axis="s" />
<FloatingPanel.ResizeTrigger axis="ne" />
<FloatingPanel.ResizeTrigger axis="se" />
<FloatingPanel.ResizeTrigger axis="sw" />
<FloatingPanel.ResizeTrigger axis="nw" />
</FloatingPanel.Content>
</FloatingPanel.Positioner>
</Portal>
</FloatingPanel.Root>
)
}
import { FloatingPanel } from '@ark-ui/solid/floating-panel'
import { ArrowDownLeft, Maximize2, Minus, XIcon } from 'lucide-solid'
import { createSignal } from 'solid-js'
import { Portal } from 'solid-js/web'
export const ControlledPosition = () => {
const [position, setPosition] = createSignal({ x: 200, y: 200 })
return (
<FloatingPanel.Root position={position()} onPositionChange={(e) => setPosition(e.position)}>
<FloatingPanel.Trigger>Toggle Panel</FloatingPanel.Trigger>
<Portal>
<FloatingPanel.Positioner>
<FloatingPanel.Content>
<FloatingPanel.DragTrigger>
<FloatingPanel.Header>
<FloatingPanel.Title>Floating Panel</FloatingPanel.Title>
<FloatingPanel.Control>
<FloatingPanel.StageTrigger stage="minimized">
<Minus />
</FloatingPanel.StageTrigger>
<FloatingPanel.StageTrigger stage="maximized">
<Maximize2 />
</FloatingPanel.StageTrigger>
<FloatingPanel.StageTrigger stage="default">
<ArrowDownLeft />
</FloatingPanel.StageTrigger>
<FloatingPanel.CloseTrigger>
<XIcon />
</FloatingPanel.CloseTrigger>
</FloatingPanel.Control>
</FloatingPanel.Header>
</FloatingPanel.DragTrigger>
<FloatingPanel.Body>
<p>Some content</p>
</FloatingPanel.Body>
<FloatingPanel.ResizeTrigger axis="n" />
<FloatingPanel.ResizeTrigger axis="e" />
<FloatingPanel.ResizeTrigger axis="w" />
<FloatingPanel.ResizeTrigger axis="s" />
<FloatingPanel.ResizeTrigger axis="ne" />
<FloatingPanel.ResizeTrigger axis="se" />
<FloatingPanel.ResizeTrigger axis="sw" />
<FloatingPanel.ResizeTrigger axis="nw" />
</FloatingPanel.Content>
</FloatingPanel.Positioner>
</Portal>
</FloatingPanel.Root>
)
}
<script setup lang="ts">
import { FloatingPanel } from '@ark-ui/vue/floating-panel'
import { ArrowDownLeft, Maximize2, Minus, XIcon } from 'lucide-vue-next'
import { ref } from 'vue'
const position = ref({ x: 200, y: 200 })
</script>
<template>
<FloatingPanel.Root v-model:position="position">
<FloatingPanel.Trigger>Toggle Panel</FloatingPanel.Trigger>
<Teleport to="body">
<FloatingPanel.Positioner>
<FloatingPanel.Content>
<FloatingPanel.DragTrigger>
<FloatingPanel.Header>
<FloatingPanel.Title>Floating Panel</FloatingPanel.Title>
<FloatingPanel.Control>
<FloatingPanel.StageTrigger stage="minimized">
<Minus />
</FloatingPanel.StageTrigger>
<FloatingPanel.StageTrigger stage="maximized">
<Maximize2 />
</FloatingPanel.StageTrigger>
<FloatingPanel.StageTrigger stage="default">
<ArrowDownLeft />
</FloatingPanel.StageTrigger>
<FloatingPanel.CloseTrigger>
<XIcon />
</FloatingPanel.CloseTrigger>
</FloatingPanel.Control>
</FloatingPanel.Header>
</FloatingPanel.DragTrigger>
<FloatingPanel.Body>
<p>Some content</p>
</FloatingPanel.Body>
<FloatingPanel.ResizeTrigger axis="n" />
<FloatingPanel.ResizeTrigger axis="e" />
<FloatingPanel.ResizeTrigger axis="w" />
<FloatingPanel.ResizeTrigger axis="s" />
<FloatingPanel.ResizeTrigger axis="ne" />
<FloatingPanel.ResizeTrigger axis="se" />
<FloatingPanel.ResizeTrigger axis="sw" />
<FloatingPanel.ResizeTrigger axis="nw" />
</FloatingPanel.Content>
</FloatingPanel.Positioner>
</Teleport>
</FloatingPanel.Root>
</template>
<script lang="ts">
import { FloatingPanel } from '@ark-ui/svelte/floating-panel'
import { Portal } from '@ark-ui/svelte/portal'
let position = $state({ x: 200, y: 200 })
</script>
<FloatingPanel.Root bind:position>
<FloatingPanel.Trigger>Toggle Panel</FloatingPanel.Trigger>
<Portal>
<FloatingPanel.Positioner>
<FloatingPanel.Content>
<FloatingPanel.DragTrigger>
<FloatingPanel.Header>
<FloatingPanel.Title>Floating Panel</FloatingPanel.Title>
<FloatingPanel.Control>
<FloatingPanel.StageTrigger stage="minimized">
<span>−</span>
</FloatingPanel.StageTrigger>
<FloatingPanel.StageTrigger stage="maximized">
<span>□</span>
</FloatingPanel.StageTrigger>
<FloatingPanel.StageTrigger stage="default">
<span>↗</span>
</FloatingPanel.StageTrigger>
<FloatingPanel.CloseTrigger>
<span>×</span>
</FloatingPanel.CloseTrigger>
</FloatingPanel.Control>
</FloatingPanel.Header>
</FloatingPanel.DragTrigger>
<FloatingPanel.Body>
<p>Some content</p>
<p>Position: x={position.x}, y={position.y}</p>
</FloatingPanel.Body>
<FloatingPanel.ResizeTrigger axis="n" />
<FloatingPanel.ResizeTrigger axis="e" />
<FloatingPanel.ResizeTrigger axis="w" />
<FloatingPanel.ResizeTrigger axis="s" />
<FloatingPanel.ResizeTrigger axis="ne" />
<FloatingPanel.ResizeTrigger axis="se" />
<FloatingPanel.ResizeTrigger axis="sw" />
<FloatingPanel.ResizeTrigger axis="nw" />
</FloatingPanel.Content>
</FloatingPanel.Positioner>
</Portal>
</FloatingPanel.Root>
Anchor position
Use the getAnchorPosition function to compute the initial position of the floating panel. This function is called when
the panel is opened and receives the triggerRect and boundaryRect.
import { FloatingPanel } from '@ark-ui/react/floating-panel'
import { Portal } from '@ark-ui/react/portal'
import { ArrowDownLeft, Maximize2, Minus, XIcon } from 'lucide-react'
export const AnchorPosition = () => (
<FloatingPanel.Root
getAnchorPosition={({ triggerRect }) => {
if (!triggerRect) return { x: 0, y: 0 }
return {
x: triggerRect.x + triggerRect.width / 2,
y: triggerRect.y + triggerRect.height / 2,
}
}}
>
<FloatingPanel.Trigger>Toggle Panel</FloatingPanel.Trigger>
<Portal>
<FloatingPanel.Positioner>
<FloatingPanel.Content>
<FloatingPanel.DragTrigger>
<FloatingPanel.Header>
<FloatingPanel.Title>Floating Panel</FloatingPanel.Title>
<FloatingPanel.Control>
<FloatingPanel.StageTrigger stage="minimized">
<Minus />
</FloatingPanel.StageTrigger>
<FloatingPanel.StageTrigger stage="maximized">
<Maximize2 />
</FloatingPanel.StageTrigger>
<FloatingPanel.StageTrigger stage="default">
<ArrowDownLeft />
</FloatingPanel.StageTrigger>
<FloatingPanel.CloseTrigger>
<XIcon />
</FloatingPanel.CloseTrigger>
</FloatingPanel.Control>
</FloatingPanel.Header>
</FloatingPanel.DragTrigger>
<FloatingPanel.Body>
<p>Some content</p>
</FloatingPanel.Body>
<FloatingPanel.ResizeTrigger axis="n" />
<FloatingPanel.ResizeTrigger axis="e" />
<FloatingPanel.ResizeTrigger axis="w" />
<FloatingPanel.ResizeTrigger axis="s" />
<FloatingPanel.ResizeTrigger axis="ne" />
<FloatingPanel.ResizeTrigger axis="se" />
<FloatingPanel.ResizeTrigger axis="sw" />
<FloatingPanel.ResizeTrigger axis="nw" />
</FloatingPanel.Content>
</FloatingPanel.Positioner>
</Portal>
</FloatingPanel.Root>
)
import { FloatingPanel } from '@ark-ui/solid/floating-panel'
import { ArrowDownLeft, Maximize2, Minus, XIcon } from 'lucide-solid'
import { Portal } from 'solid-js/web'
export const AnchorPosition = () => (
<FloatingPanel.Root
getAnchorPosition={({ triggerRect }) => {
if (!triggerRect) return { x: 0, y: 0 }
return {
x: triggerRect.x + triggerRect.width / 2,
y: triggerRect.y + triggerRect.height / 2,
}
}}
>
<FloatingPanel.Trigger>Toggle Panel</FloatingPanel.Trigger>
<Portal>
<FloatingPanel.Positioner>
<FloatingPanel.Content>
<FloatingPanel.DragTrigger>
<FloatingPanel.Header>
<FloatingPanel.Title>Floating Panel</FloatingPanel.Title>
<FloatingPanel.Control>
<FloatingPanel.StageTrigger stage="minimized">
<Minus />
</FloatingPanel.StageTrigger>
<FloatingPanel.StageTrigger stage="maximized">
<Maximize2 />
</FloatingPanel.StageTrigger>
<FloatingPanel.StageTrigger stage="default">
<ArrowDownLeft />
</FloatingPanel.StageTrigger>
<FloatingPanel.CloseTrigger>
<XIcon />
</FloatingPanel.CloseTrigger>
</FloatingPanel.Control>
</FloatingPanel.Header>
</FloatingPanel.DragTrigger>
<FloatingPanel.Body>
<p>Some content</p>
</FloatingPanel.Body>
<FloatingPanel.ResizeTrigger axis="n" />
<FloatingPanel.ResizeTrigger axis="e" />
<FloatingPanel.ResizeTrigger axis="w" />
<FloatingPanel.ResizeTrigger axis="s" />
<FloatingPanel.ResizeTrigger axis="ne" />
<FloatingPanel.ResizeTrigger axis="se" />
<FloatingPanel.ResizeTrigger axis="sw" />
<FloatingPanel.ResizeTrigger axis="nw" />
</FloatingPanel.Content>
</FloatingPanel.Positioner>
</Portal>
</FloatingPanel.Root>
)
<script setup lang="ts">
import { FloatingPanel } from '@ark-ui/vue/floating-panel'
import { ArrowDownLeft, Maximize2, Minus, XIcon } from 'lucide-vue-next'
interface Rect {
x: number
y: number
width: number
height: number
}
interface AnchorPositionDetails {
triggerRect: Rect | null
boundaryRect: Rect | null
}
const getAnchorPosition = ({ triggerRect }: AnchorPositionDetails) => {
if (!triggerRect) return { x: 0, y: 0 }
return {
x: triggerRect.x + triggerRect.width / 2,
y: triggerRect.y + triggerRect.height / 2,
}
}
</script>
<template>
<FloatingPanel.Root :get-anchor-position="getAnchorPosition">
<FloatingPanel.Trigger>Toggle Panel</FloatingPanel.Trigger>
<Teleport to="body">
<FloatingPanel.Positioner>
<FloatingPanel.Content>
<FloatingPanel.DragTrigger>
<FloatingPanel.Header>
<FloatingPanel.Title>Floating Panel</FloatingPanel.Title>
<FloatingPanel.Control>
<FloatingPanel.StageTrigger stage="minimized">
<Minus />
</FloatingPanel.StageTrigger>
<FloatingPanel.StageTrigger stage="maximized">
<Maximize2 />
</FloatingPanel.StageTrigger>
<FloatingPanel.StageTrigger stage="default">
<ArrowDownLeft />
</FloatingPanel.StageTrigger>
<FloatingPanel.CloseTrigger>
<XIcon />
</FloatingPanel.CloseTrigger>
</FloatingPanel.Control>
</FloatingPanel.Header>
</FloatingPanel.DragTrigger>
<FloatingPanel.Body>
<p>Some content</p>
</FloatingPanel.Body>
<FloatingPanel.ResizeTrigger axis="n" />
<FloatingPanel.ResizeTrigger axis="e" />
<FloatingPanel.ResizeTrigger axis="w" />
<FloatingPanel.ResizeTrigger axis="s" />
<FloatingPanel.ResizeTrigger axis="ne" />
<FloatingPanel.ResizeTrigger axis="se" />
<FloatingPanel.ResizeTrigger axis="sw" />
<FloatingPanel.ResizeTrigger axis="nw" />
</FloatingPanel.Content>
</FloatingPanel.Positioner>
</Teleport>
</FloatingPanel.Root>
</template>
<script lang="ts">
import { FloatingPanel } from '@ark-ui/svelte/floating-panel'
import { Portal } from '@ark-ui/svelte/portal'
</script>
<FloatingPanel.Root
getAnchorPosition={({ triggerRect }) => {
if (!triggerRect) return { x: 0, y: 0 }
return {
x: triggerRect.x + triggerRect.width / 2,
y: triggerRect.y + triggerRect.height / 2,
}
}}
>
<FloatingPanel.Trigger>Toggle Panel</FloatingPanel.Trigger>
<Portal>
<FloatingPanel.Positioner>
<FloatingPanel.Content>
<FloatingPanel.DragTrigger>
<FloatingPanel.Header>
<FloatingPanel.Title>Floating Panel</FloatingPanel.Title>
<FloatingPanel.Control>
<FloatingPanel.StageTrigger stage="minimized">
<span>−</span>
</FloatingPanel.StageTrigger>
<FloatingPanel.StageTrigger stage="maximized">
<span>□</span>
</FloatingPanel.StageTrigger>
<FloatingPanel.StageTrigger stage="default">
<span>↗</span>
</FloatingPanel.StageTrigger>
<FloatingPanel.CloseTrigger>
<span>×</span>
</FloatingPanel.CloseTrigger>
</FloatingPanel.Control>
</FloatingPanel.Header>
</FloatingPanel.DragTrigger>
<FloatingPanel.Body>
<p>Some content</p>
<p>Anchored to trigger center</p>
</FloatingPanel.Body>
<FloatingPanel.ResizeTrigger axis="n" />
<FloatingPanel.ResizeTrigger axis="e" />
<FloatingPanel.ResizeTrigger axis="w" />
<FloatingPanel.ResizeTrigger axis="s" />
<FloatingPanel.ResizeTrigger axis="ne" />
<FloatingPanel.ResizeTrigger axis="se" />
<FloatingPanel.ResizeTrigger axis="sw" />
<FloatingPanel.ResizeTrigger axis="nw" />
</FloatingPanel.Content>
</FloatingPanel.Positioner>
</Portal>
</FloatingPanel.Root>
Controlling the open state
To control the open state of the floating panel programmatically, you can pass the open and onOpenChange prop to the
machine.
import { FloatingPanel } from '@ark-ui/react/floating-panel'
import { Portal } from '@ark-ui/react/portal'
import { ArrowDownLeft, Maximize2, Minus, XIcon } from 'lucide-react'
import { useState } from 'react'
export const ControlledOpen = () => {
const [open, setOpen] = useState(false)
return (
<FloatingPanel.Root open={open} onOpenChange={(e) => setOpen(e.open)}>
<FloatingPanel.Trigger>Toggle Panel</FloatingPanel.Trigger>
<Portal>
<FloatingPanel.Positioner>
<FloatingPanel.Content>
<FloatingPanel.DragTrigger>
<FloatingPanel.Header>
<FloatingPanel.Title>Floating Panel</FloatingPanel.Title>
<FloatingPanel.Control>
<FloatingPanel.StageTrigger stage="minimized">
<Minus />
</FloatingPanel.StageTrigger>
<FloatingPanel.StageTrigger stage="maximized">
<Maximize2 />
</FloatingPanel.StageTrigger>
<FloatingPanel.StageTrigger stage="default">
<ArrowDownLeft />
</FloatingPanel.StageTrigger>
<FloatingPanel.CloseTrigger>
<XIcon />
</FloatingPanel.CloseTrigger>
</FloatingPanel.Control>
</FloatingPanel.Header>
</FloatingPanel.DragTrigger>
<FloatingPanel.Body>
<p>Some content</p>
</FloatingPanel.Body>
<FloatingPanel.ResizeTrigger axis="n" />
<FloatingPanel.ResizeTrigger axis="e" />
<FloatingPanel.ResizeTrigger axis="w" />
<FloatingPanel.ResizeTrigger axis="s" />
<FloatingPanel.ResizeTrigger axis="ne" />
<FloatingPanel.ResizeTrigger axis="se" />
<FloatingPanel.ResizeTrigger axis="sw" />
<FloatingPanel.ResizeTrigger axis="nw" />
</FloatingPanel.Content>
</FloatingPanel.Positioner>
</Portal>
</FloatingPanel.Root>
)
}
import { FloatingPanel } from '@ark-ui/solid/floating-panel'
import { ArrowDownLeft, Maximize2, Minus, XIcon } from 'lucide-solid'
import { createSignal } from 'solid-js'
import { Portal } from 'solid-js/web'
export const ControlledOpen = () => {
const [open, setOpen] = createSignal(false)
return (
<FloatingPanel.Root open={open()} onOpenChange={(e) => setOpen(e.open)}>
<FloatingPanel.Trigger>Toggle Panel</FloatingPanel.Trigger>
<Portal>
<FloatingPanel.Positioner>
<FloatingPanel.Content>
<FloatingPanel.DragTrigger>
<FloatingPanel.Header>
<FloatingPanel.Title>Floating Panel</FloatingPanel.Title>
<FloatingPanel.Control>
<FloatingPanel.StageTrigger stage="minimized">
<Minus />
</FloatingPanel.StageTrigger>
<FloatingPanel.StageTrigger stage="maximized">
<Maximize2 />
</FloatingPanel.StageTrigger>
<FloatingPanel.StageTrigger stage="default">
<ArrowDownLeft />
</FloatingPanel.StageTrigger>
<FloatingPanel.CloseTrigger>
<XIcon />
</FloatingPanel.CloseTrigger>
</FloatingPanel.Control>
</FloatingPanel.Header>
</FloatingPanel.DragTrigger>
<FloatingPanel.Body>
<p>Some content</p>
</FloatingPanel.Body>
<FloatingPanel.ResizeTrigger axis="n" />
<FloatingPanel.ResizeTrigger axis="e" />
<FloatingPanel.ResizeTrigger axis="w" />
<FloatingPanel.ResizeTrigger axis="s" />
<FloatingPanel.ResizeTrigger axis="ne" />
<FloatingPanel.ResizeTrigger axis="se" />
<FloatingPanel.ResizeTrigger axis="sw" />
<FloatingPanel.ResizeTrigger axis="nw" />
</FloatingPanel.Content>
</FloatingPanel.Positioner>
</Portal>
</FloatingPanel.Root>
)
}
<script setup lang="ts">
import { FloatingPanel } from '@ark-ui/vue/floating-panel'
import { ArrowDownLeft, Maximize2, Minus, XIcon } from 'lucide-vue-next'
import { ref } from 'vue'
const open = ref(false)
</script>
<template>
<FloatingPanel.Root v-model:open="open">
<FloatingPanel.Trigger>Toggle Panel</FloatingPanel.Trigger>
<Teleport to="body">
<FloatingPanel.Positioner>
<FloatingPanel.Content>
<FloatingPanel.DragTrigger>
<FloatingPanel.Header>
<FloatingPanel.Title>Floating Panel</FloatingPanel.Title>
<FloatingPanel.Control>
<FloatingPanel.StageTrigger stage="minimized">
<Minus />
</FloatingPanel.StageTrigger>
<FloatingPanel.StageTrigger stage="maximized">
<Maximize2 />
</FloatingPanel.StageTrigger>
<FloatingPanel.StageTrigger stage="default">
<ArrowDownLeft />
</FloatingPanel.StageTrigger>
<FloatingPanel.CloseTrigger>
<XIcon />
</FloatingPanel.CloseTrigger>
</FloatingPanel.Control>
</FloatingPanel.Header>
</FloatingPanel.DragTrigger>
<FloatingPanel.Body>
<p>Some content</p>
</FloatingPanel.Body>
<FloatingPanel.ResizeTrigger axis="n" />
<FloatingPanel.ResizeTrigger axis="e" />
<FloatingPanel.ResizeTrigger axis="w" />
<FloatingPanel.ResizeTrigger axis="s" />
<FloatingPanel.ResizeTrigger axis="ne" />
<FloatingPanel.ResizeTrigger axis="se" />
<FloatingPanel.ResizeTrigger axis="sw" />
<FloatingPanel.ResizeTrigger axis="nw" />
</FloatingPanel.Content>
</FloatingPanel.Positioner>
</Teleport>
</FloatingPanel.Root>
</template>
<script lang="ts">
import { FloatingPanel } from '@ark-ui/svelte/floating-panel'
import { Portal } from '@ark-ui/svelte/portal'
let open = $state(false)
</script>
<FloatingPanel.Root bind:open>
<FloatingPanel.Trigger>Toggle Panel</FloatingPanel.Trigger>
<Portal>
<FloatingPanel.Positioner>
<FloatingPanel.Content>
<FloatingPanel.DragTrigger>
<FloatingPanel.Header>
<FloatingPanel.Title>Floating Panel</FloatingPanel.Title>
<FloatingPanel.Control>
<FloatingPanel.StageTrigger stage="minimized">
<span>−</span>
</FloatingPanel.StageTrigger>
<FloatingPanel.StageTrigger stage="maximized">
<span>□</span>
</FloatingPanel.StageTrigger>
<FloatingPanel.StageTrigger stage="default">
<span>↗</span>
</FloatingPanel.StageTrigger>
<FloatingPanel.CloseTrigger>
<span>×</span>
</FloatingPanel.CloseTrigger>
</FloatingPanel.Control>
</FloatingPanel.Header>
</FloatingPanel.DragTrigger>
<FloatingPanel.Body>
<p>Some content</p>
<p>Panel is {open ? 'open' : 'closed'}</p>
</FloatingPanel.Body>
<FloatingPanel.ResizeTrigger axis="n" />
<FloatingPanel.ResizeTrigger axis="e" />
<FloatingPanel.ResizeTrigger axis="w" />
<FloatingPanel.ResizeTrigger axis="s" />
<FloatingPanel.ResizeTrigger axis="ne" />
<FloatingPanel.ResizeTrigger axis="se" />
<FloatingPanel.ResizeTrigger axis="sw" />
<FloatingPanel.ResizeTrigger axis="nw" />
</FloatingPanel.Content>
</FloatingPanel.Positioner>
</Portal>
</FloatingPanel.Root>
Lazy mounting
To lazy mount the floating panel, you can pass the lazyMount prop to the machine.
import { FloatingPanel } from '@ark-ui/react/floating-panel'
import { Portal } from '@ark-ui/react/portal'
import { ArrowDownLeft, Maximize2, Minus, XIcon } from 'lucide-react'
export const LazyMount = () => (
<FloatingPanel.Root lazyMount onExitComplete={() => console.log('onExitComplete invoked')}>
<FloatingPanel.Trigger>Toggle Panel</FloatingPanel.Trigger>
<Portal>
<FloatingPanel.Positioner>
<FloatingPanel.Content>
<FloatingPanel.DragTrigger>
<FloatingPanel.Header>
<FloatingPanel.Title>Floating Panel</FloatingPanel.Title>
<FloatingPanel.Control>
<FloatingPanel.StageTrigger stage="minimized">
<Minus />
</FloatingPanel.StageTrigger>
<FloatingPanel.StageTrigger stage="maximized">
<Maximize2 />
</FloatingPanel.StageTrigger>
<FloatingPanel.StageTrigger stage="default">
<ArrowDownLeft />
</FloatingPanel.StageTrigger>
<FloatingPanel.CloseTrigger>
<XIcon />
</FloatingPanel.CloseTrigger>
</FloatingPanel.Control>
</FloatingPanel.Header>
</FloatingPanel.DragTrigger>
<FloatingPanel.Body>
<p>Some content</p>
</FloatingPanel.Body>
<FloatingPanel.ResizeTrigger axis="n" />
<FloatingPanel.ResizeTrigger axis="e" />
<FloatingPanel.ResizeTrigger axis="w" />
<FloatingPanel.ResizeTrigger axis="s" />
<FloatingPanel.ResizeTrigger axis="ne" />
<FloatingPanel.ResizeTrigger axis="se" />
<FloatingPanel.ResizeTrigger axis="sw" />
<FloatingPanel.ResizeTrigger axis="nw" />
</FloatingPanel.Content>
</FloatingPanel.Positioner>
</Portal>
</FloatingPanel.Root>
)
import { FloatingPanel } from '@ark-ui/solid/floating-panel'
import { ArrowDownLeft, Maximize2, Minus, XIcon } from 'lucide-solid'
import { Portal } from 'solid-js/web'
export const LazyMount = () => (
<FloatingPanel.Root lazyMount onExitComplete={() => console.log('onExitComplete invoked')}>
<FloatingPanel.Trigger>Toggle Panel</FloatingPanel.Trigger>
<Portal>
<FloatingPanel.Positioner>
<FloatingPanel.Content>
<FloatingPanel.DragTrigger>
<FloatingPanel.Header>
<FloatingPanel.Title>Floating Panel</FloatingPanel.Title>
<FloatingPanel.Control>
<FloatingPanel.StageTrigger stage="minimized">
<Minus />
</FloatingPanel.StageTrigger>
<FloatingPanel.StageTrigger stage="maximized">
<Maximize2 />
</FloatingPanel.StageTrigger>
<FloatingPanel.StageTrigger stage="default">
<ArrowDownLeft />
</FloatingPanel.StageTrigger>
<FloatingPanel.CloseTrigger>
<XIcon />
</FloatingPanel.CloseTrigger>
</FloatingPanel.Control>
</FloatingPanel.Header>
</FloatingPanel.DragTrigger>
<FloatingPanel.Body>
<p>Some content</p>
</FloatingPanel.Body>
<FloatingPanel.ResizeTrigger axis="n" />
<FloatingPanel.ResizeTrigger axis="e" />
<FloatingPanel.ResizeTrigger axis="w" />
<FloatingPanel.ResizeTrigger axis="s" />
<FloatingPanel.ResizeTrigger axis="ne" />
<FloatingPanel.ResizeTrigger axis="se" />
<FloatingPanel.ResizeTrigger axis="sw" />
<FloatingPanel.ResizeTrigger axis="nw" />
</FloatingPanel.Content>
</FloatingPanel.Positioner>
</Portal>
</FloatingPanel.Root>
)
<script setup lang="ts">
import { FloatingPanel } from '@ark-ui/vue/floating-panel'
import { ArrowDownLeft, Maximize2, Minus, XIcon } from 'lucide-vue-next'
</script>
<template>
<FloatingPanel.Root lazy-mount @exit-complete="() => console.log('onExitComplete invoked')">
<FloatingPanel.Trigger>Toggle Panel</FloatingPanel.Trigger>
<Teleport to="body">
<FloatingPanel.Positioner>
<FloatingPanel.Content>
<FloatingPanel.DragTrigger>
<FloatingPanel.Header>
<FloatingPanel.Title>Floating Panel</FloatingPanel.Title>
<FloatingPanel.Control>
<FloatingPanel.StageTrigger stage="minimized">
<Minus />
</FloatingPanel.StageTrigger>
<FloatingPanel.StageTrigger stage="maximized">
<Maximize2 />
</FloatingPanel.StageTrigger>
<FloatingPanel.StageTrigger stage="default">
<ArrowDownLeft />
</FloatingPanel.StageTrigger>
<FloatingPanel.CloseTrigger>
<XIcon />
</FloatingPanel.CloseTrigger>
</FloatingPanel.Control>
</FloatingPanel.Header>
</FloatingPanel.DragTrigger>
<FloatingPanel.Body>
<p>Some content</p>
</FloatingPanel.Body>
<FloatingPanel.ResizeTrigger axis="n" />
<FloatingPanel.ResizeTrigger axis="e" />
<FloatingPanel.ResizeTrigger axis="w" />
<FloatingPanel.ResizeTrigger axis="s" />
<FloatingPanel.ResizeTrigger axis="ne" />
<FloatingPanel.ResizeTrigger axis="se" />
<FloatingPanel.ResizeTrigger axis="sw" />
<FloatingPanel.ResizeTrigger axis="nw" />
</FloatingPanel.Content>
</FloatingPanel.Positioner>
</Teleport>
</FloatingPanel.Root>
</template>
<script lang="ts">
import { FloatingPanel } from '@ark-ui/svelte/floating-panel'
import { Portal } from '@ark-ui/svelte/portal'
import { ArrowDownLeft, Maximize2, Minus, XIcon } from 'lucide-svelte'
</script>
<FloatingPanel.Root lazyMount onExitComplete={() => console.log('onExitComplete invoked')}>
<FloatingPanel.Trigger>Toggle Panel</FloatingPanel.Trigger>
<Portal>
<FloatingPanel.Positioner>
<FloatingPanel.Content>
<FloatingPanel.DragTrigger>
<FloatingPanel.Header>
<FloatingPanel.Title>Floating Panel</FloatingPanel.Title>
<FloatingPanel.Control>
<FloatingPanel.StageTrigger stage="minimized">
<Minus />
</FloatingPanel.StageTrigger>
<FloatingPanel.StageTrigger stage="maximized">
<Maximize2 />
</FloatingPanel.StageTrigger>
<FloatingPanel.StageTrigger stage="default">
<ArrowDownLeft />
</FloatingPanel.StageTrigger>
<FloatingPanel.CloseTrigger>
<XIcon />
</FloatingPanel.CloseTrigger>
</FloatingPanel.Control>
</FloatingPanel.Header>
</FloatingPanel.DragTrigger>
<FloatingPanel.Body>
<p>Some content</p>
</FloatingPanel.Body>
<FloatingPanel.ResizeTrigger axis="n" />
<FloatingPanel.ResizeTrigger axis="e" />
<FloatingPanel.ResizeTrigger axis="w" />
<FloatingPanel.ResizeTrigger axis="s" />
<FloatingPanel.ResizeTrigger axis="ne" />
<FloatingPanel.ResizeTrigger axis="se" />
<FloatingPanel.ResizeTrigger axis="sw" />
<FloatingPanel.ResizeTrigger axis="nw" />
</FloatingPanel.Content>
</FloatingPanel.Positioner>
</Portal>
</FloatingPanel.Root>
Context
To access the context of the floating panel, you can use the useFloatingPanelContext hook or the
FloatingPanel.Context component.
import { FloatingPanel } from '@ark-ui/react/floating-panel'
import { Portal } from '@ark-ui/react/portal'
import { ArrowDownLeft, Maximize2, Minus, XIcon } from 'lucide-react'
export const RenderFn = () => (
<FloatingPanel.Root>
<FloatingPanel.Trigger>Toggle Panel</FloatingPanel.Trigger>
<FloatingPanel.Context>
{(floatingPanel) => <p>floatingPanel. is {floatingPanel.open ? 'open' : 'closed'}</p>}
</FloatingPanel.Context>
<Portal>
<FloatingPanel.Positioner>
<FloatingPanel.Content>
<FloatingPanel.DragTrigger>
<FloatingPanel.Header>
<FloatingPanel.Title>Floating Panel</FloatingPanel.Title>
<FloatingPanel.Control>
<FloatingPanel.StageTrigger stage="minimized">
<Minus />
</FloatingPanel.StageTrigger>
<FloatingPanel.StageTrigger stage="maximized">
<Maximize2 />
</FloatingPanel.StageTrigger>
<FloatingPanel.StageTrigger stage="default">
<ArrowDownLeft />
</FloatingPanel.StageTrigger>
<FloatingPanel.CloseTrigger>
<XIcon />
</FloatingPanel.CloseTrigger>
</FloatingPanel.Control>
</FloatingPanel.Header>
</FloatingPanel.DragTrigger>
<FloatingPanel.Body>
<p>Some content</p>
</FloatingPanel.Body>
<FloatingPanel.ResizeTrigger axis="n" />
<FloatingPanel.ResizeTrigger axis="e" />
<FloatingPanel.ResizeTrigger axis="w" />
<FloatingPanel.ResizeTrigger axis="s" />
<FloatingPanel.ResizeTrigger axis="ne" />
<FloatingPanel.ResizeTrigger axis="se" />
<FloatingPanel.ResizeTrigger axis="sw" />
<FloatingPanel.ResizeTrigger axis="nw" />
</FloatingPanel.Content>
</FloatingPanel.Positioner>
</Portal>
</FloatingPanel.Root>
)
import { FloatingPanel } from '@ark-ui/solid/floating-panel'
import { ArrowDownLeft, Maximize2, Minus, XIcon } from 'lucide-solid'
import { Portal } from 'solid-js/web'
export const RenderFn = () => (
<FloatingPanel.Root>
<FloatingPanel.Trigger>Toggle Panel</FloatingPanel.Trigger>
<FloatingPanel.Context>
{(floatingPanel) => <p>floatingPanel is {floatingPanel().open ? 'open' : 'closed'}</p>}
</FloatingPanel.Context>
<Portal>
<FloatingPanel.Positioner>
<FloatingPanel.Content>
<FloatingPanel.DragTrigger>
<FloatingPanel.Header>
<FloatingPanel.Title>Floating Panel</FloatingPanel.Title>
<FloatingPanel.Control>
<FloatingPanel.StageTrigger stage="minimized">
<Minus />
</FloatingPanel.StageTrigger>
<FloatingPanel.StageTrigger stage="maximized">
<Maximize2 />
</FloatingPanel.StageTrigger>
<FloatingPanel.StageTrigger stage="default">
<ArrowDownLeft />
</FloatingPanel.StageTrigger>
<FloatingPanel.CloseTrigger>
<XIcon />
</FloatingPanel.CloseTrigger>
</FloatingPanel.Control>
</FloatingPanel.Header>
</FloatingPanel.DragTrigger>
<FloatingPanel.Body>
<p>Some content</p>
</FloatingPanel.Body>
<FloatingPanel.ResizeTrigger axis="n" />
<FloatingPanel.ResizeTrigger axis="e" />
<FloatingPanel.ResizeTrigger axis="w" />
<FloatingPanel.ResizeTrigger axis="s" />
<FloatingPanel.ResizeTrigger axis="ne" />
<FloatingPanel.ResizeTrigger axis="se" />
<FloatingPanel.ResizeTrigger axis="sw" />
<FloatingPanel.ResizeTrigger axis="nw" />
</FloatingPanel.Content>
</FloatingPanel.Positioner>
</Portal>
</FloatingPanel.Root>
)
<script setup lang="ts">
import { FloatingPanel } from '@ark-ui/vue/floating-panel'
import { ArrowDownLeft, Maximize2, Minus, XIcon } from 'lucide-vue-next'
</script>
<template>
<FloatingPanel.Root>
<FloatingPanel.Context v-slot="floatingPanel">
<p>floatingPanel is {{ floatingPanel.open ? 'open' : 'closed' }}</p>
</FloatingPanel.Context>
<FloatingPanel.Trigger>Toggle Panel</FloatingPanel.Trigger>
<Teleport to="body">
<FloatingPanel.Positioner>
<FloatingPanel.Content>
<FloatingPanel.DragTrigger>
<FloatingPanel.Header>
<FloatingPanel.Title>Floating Panel</FloatingPanel.Title>
<FloatingPanel.Control>
<FloatingPanel.StageTrigger stage="minimized">
<Minus />
</FloatingPanel.StageTrigger>
<FloatingPanel.StageTrigger stage="maximized">
<Maximize2 />
</FloatingPanel.StageTrigger>
<FloatingPanel.StageTrigger stage="default">
<ArrowDownLeft />
</FloatingPanel.StageTrigger>
<FloatingPanel.CloseTrigger>
<XIcon />
</FloatingPanel.CloseTrigger>
</FloatingPanel.Control>
</FloatingPanel.Header>
</FloatingPanel.DragTrigger>
<FloatingPanel.Body>
<p>Some content</p>
</FloatingPanel.Body>
<FloatingPanel.ResizeTrigger axis="n" />
<FloatingPanel.ResizeTrigger axis="e" />
<FloatingPanel.ResizeTrigger axis="w" />
<FloatingPanel.ResizeTrigger axis="s" />
<FloatingPanel.ResizeTrigger axis="ne" />
<FloatingPanel.ResizeTrigger axis="se" />
<FloatingPanel.ResizeTrigger axis="sw" />
<FloatingPanel.ResizeTrigger axis="nw" />
</FloatingPanel.Content>
</FloatingPanel.Positioner>
</Teleport>
</FloatingPanel.Root>
</template>
<script lang="ts">
import { FloatingPanel } from '@ark-ui/svelte/floating-panel'
import { Portal } from '@ark-ui/svelte/portal'
</script>
<FloatingPanel.Root>
<FloatingPanel.Trigger>Toggle Panel</FloatingPanel.Trigger>
<FloatingPanel.Context>
{#snippet render(floatingPanel)}
<p>Panel is {floatingPanel().open ? 'open' : 'closed'}</p>
{/snippet}
</FloatingPanel.Context>
<Portal>
<FloatingPanel.Positioner>
<FloatingPanel.Content>
<FloatingPanel.DragTrigger>
<FloatingPanel.Header>
<FloatingPanel.Title>Floating Panel</FloatingPanel.Title>
<FloatingPanel.Control>
<FloatingPanel.StageTrigger stage="minimized">
<span>−</span>
</FloatingPanel.StageTrigger>
<FloatingPanel.StageTrigger stage="maximized">
<span>□</span>
</FloatingPanel.StageTrigger>
<FloatingPanel.StageTrigger stage="default">
<span>↗</span>
</FloatingPanel.StageTrigger>
<FloatingPanel.CloseTrigger>
<span>×</span>
</FloatingPanel.CloseTrigger>
</FloatingPanel.Control>
</FloatingPanel.Header>
</FloatingPanel.DragTrigger>
<FloatingPanel.Body>
<p>Some content</p>
</FloatingPanel.Body>
<FloatingPanel.ResizeTrigger axis="n" />
<FloatingPanel.ResizeTrigger axis="e" />
<FloatingPanel.ResizeTrigger axis="w" />
<FloatingPanel.ResizeTrigger axis="s" />
<FloatingPanel.ResizeTrigger axis="ne" />
<FloatingPanel.ResizeTrigger axis="se" />
<FloatingPanel.ResizeTrigger axis="sw" />
<FloatingPanel.ResizeTrigger axis="nw" />
</FloatingPanel.Content>
</FloatingPanel.Positioner>
</Portal>
</FloatingPanel.Root>
API Reference
Root
| Prop | Default | Type |
|---|---|---|
allowOverflow | true | booleanWhether the panel should be strictly contained within the boundary when dragging |
closeOnEscape | booleanWhether the panel should close when the escape key is pressed | |
defaultOpen | false | booleanThe initial open state of the panel when rendered. Use when you don't need to control the open state of the panel. |
defaultPosition | PointThe initial position of the panel when rendered. Use when you don't need to control the position of the panel. | |
defaultSize | SizeThe default size of the panel | |
dir | 'ltr' | 'ltr' | 'rtl'The document's text/writing direction. |
disabled | booleanWhether the panel is disabled | |
draggable | true | booleanWhether the panel is draggable |
getAnchorPosition | (details: AnchorPositionDetails) => PointFunction that returns the initial position of the panel when it is opened. If provided, will be used instead of the default position. | |
getBoundaryEl | () => HTMLElement | nullThe boundary of the panel. Useful for recalculating the boundary rect when the it is resized. | |
gridSize | 1 | numberThe snap grid for the panel |
id | stringThe unique identifier of the machine. | |
ids | Partial<{ trigger: string; positioner: string; content: string; title: string; header: string }>The ids of the elements in the floating panel. Useful for composition. | |
immediate | booleanWhether to synchronize the present change immediately or defer it to the next frame | |
lazyMount | false | booleanWhether to enable lazy mounting |
lockAspectRatio | booleanWhether the panel is locked to its aspect ratio | |
maxSize | SizeThe maximum size of the panel | |
minSize | SizeThe minimum size of the panel | |
onExitComplete | VoidFunctionFunction called when the animation ends in the closed state | |
onOpenChange | (details: OpenChangeDetails) => voidFunction called when the panel is opened or closed | |
onPositionChange | (details: PositionChangeDetails) => voidFunction called when the position of the panel changes via dragging | |
onPositionChangeEnd | (details: PositionChangeDetails) => voidFunction called when the position of the panel changes via dragging ends | |
onSizeChange | (details: SizeChangeDetails) => voidFunction called when the size of the panel changes via resizing | |
onSizeChangeEnd | (details: SizeChangeDetails) => voidFunction called when the size of the panel changes via resizing ends | |
onStageChange | (details: StageChangeDetails) => voidFunction called when the stage of the panel changes | |
open | booleanThe controlled open state of the panel | |
persistRect | booleanWhether the panel size and position should be preserved when it is closed | |
position | PointThe controlled position of the panel | |
present | booleanWhether the node is present (controlled by the user) | |
resizable | true | booleanWhether the panel is resizable |
size | SizeThe size of the panel | |
skipAnimationOnMount | false | booleanWhether to allow the initial presence animation. |
strategy | 'fixed' | 'absolute' | 'fixed'The strategy to use for positioning |
translations | IntlTranslationsThe translations for the floating panel. | |
unmountOnExit | false | booleanWhether to unmount on exit. |
Body
| Prop | Default | Type |
|---|---|---|
asChild | booleanUse the provided child element as the default rendered element, combining their props and behavior. For more details, read our Composition guide. |
| Data Attribute | Value |
|---|---|
[data-scope] | floating-panel |
[data-part] | body |
[data-dragging] | Present when in the dragging state |
[data-minimized] | Present when minimized |
[data-maximized] | Present when maximized |
[data-staged] | Present when not in default stage |
CloseTrigger
| Prop | Default | Type |
|---|---|---|
asChild | booleanUse the provided child element as the default rendered element, combining their props and behavior. For more details, read our Composition guide. |
Content
| Prop | Default | Type |
|---|---|---|
asChild | booleanUse the provided child element as the default rendered element, combining their props and behavior. For more details, read our Composition guide. |
| Data Attribute | Value |
|---|---|
[data-scope] | floating-panel |
[data-part] | content |
[data-state] | "open" | "closed" |
[data-dragging] | Present when in the dragging state |
[data-topmost] | Present when topmost |
[data-behind] | Present when not topmost |
[data-minimized] | Present when minimized |
[data-maximized] | Present when maximized |
[data-staged] | Present when not in default stage |
Control
| Prop | Default | Type |
|---|---|---|
asChild | booleanUse the provided child element as the default rendered element, combining their props and behavior. For more details, read our Composition guide. |
| Data Attribute | Value |
|---|---|
[data-scope] | floating-panel |
[data-part] | control |
[data-disabled] | Present when disabled |
[data-stage] | The stage of the control |
[data-minimized] | Present when minimized |
[data-maximized] | Present when maximized |
[data-staged] | Present when not in default stage |
DragTrigger
| Prop | Default | Type |
|---|---|---|
asChild | booleanUse the provided child element as the default rendered element, combining their props and behavior. For more details, read our Composition guide. |
| Data Attribute | Value |
|---|---|
[data-scope] | floating-panel |
[data-part] | drag-trigger |
[data-disabled] | Present when disabled |
Header
| Prop | Default | Type |
|---|---|---|
asChild | booleanUse the provided child element as the default rendered element, combining their props and behavior. For more details, read our Composition guide. |
| Data Attribute | Value |
|---|---|
[data-scope] | floating-panel |
[data-part] | header |
[data-dragging] | Present when in the dragging state |
[data-topmost] | Present when topmost |
[data-behind] | Present when not topmost |
[data-minimized] | Present when minimized |
[data-maximized] | Present when maximized |
[data-staged] | Present when not in default stage |
Positioner
| Prop | Default | Type |
|---|---|---|
asChild | booleanUse the provided child element as the default rendered element, combining their props and behavior. For more details, read our Composition guide. |
| CSS Variable | Description |
|---|---|
--width | The width of the element |
--height | The height of the element |
--x | The x position for transform |
--y | The y position for transform |
--transform-origin | The transform origin for animations |
--reference-width | The width of the reference element |
--available-width | The available width in viewport |
--available-height | The available height in viewport |
--z-index | The z-index value |
--reference-height | The height of the root |
ResizeTrigger
| Prop | Default | Type |
|---|---|---|
axis | ResizeTriggerAxisThe axis of the resize handle | |
asChild | booleanUse the provided child element as the default rendered element, combining their props and behavior. For more details, read our Composition guide. |
| Data Attribute | Value |
|---|---|
[data-scope] | floating-panel |
[data-part] | resize-trigger |
[data-disabled] | Present when disabled |
[data-axis] | The axis to resize |
RootProvider
| Prop | Default | Type |
|---|---|---|
value | UseFloatingPanelReturn | |
immediate | booleanWhether to synchronize the present change immediately or defer it to the next frame | |
lazyMount | false | booleanWhether to enable lazy mounting |
onExitComplete | VoidFunctionFunction called when the animation ends in the closed state | |
skipAnimationOnMount | false | booleanWhether to allow the initial presence animation. |
unmountOnExit | false | booleanWhether to unmount on exit. |
StageTrigger
| Prop | Default | Type |
|---|---|---|
stage | StageThe stage of the panel | |
asChild | booleanUse the provided child element as the default rendered element, combining their props and behavior. For more details, read our Composition guide. |
Title
| Prop | Default | Type |
|---|---|---|
asChild | booleanUse the provided child element as the default rendered element, combining their props and behavior. For more details, read our Composition guide. |
Trigger
| Prop | Default | Type |
|---|---|---|
asChild | booleanUse the provided child element as the default rendered element, combining their props and behavior. For more details, read our Composition guide. |
| Data Attribute | Value |
|---|---|
[data-scope] | floating-panel |
[data-part] | trigger |
[data-state] | "open" | "closed" |
[data-dragging] | Present when in the dragging state |