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-part
attribute 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>
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>
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>
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>
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>
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>
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>