# or
yarn add @zag-js/floating-panel @zag-js/svelte
```

## 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.



## Usage

First, import the floating panel package into your project

```jsx
import * as floatingPanel from "@zag-js/floating-panel"
```

The floating panel package exports two key functions:

- `machine` â The state machine logic for the floating panel widget.
- `connect` â The function that translates the machine's state to JSX attributes
  and event handlers.

Next, import the required hooks and functions for your framework and use the
floating panel machine in your project ð¥

```svelte
<script lang="ts">
  import * as floatingPanel from "@zag-js/floating-panel"
  import { normalizeProps, useMachine } from "@zag-js/svelte"
  import { ArrowDownLeft, Maximize2, Minus, XIcon } from "lucide-svelte"

  const id = $props.id()
  const service = useMachine(floatingPanel.machine, { id })

  const api = $derived(floatingPanel.connect(service, normalizeProps))
</script>

<button {...api.getTriggerProps()}>Toggle Panel</button>

<div {...api.getPositionerProps()}>
  <div {...api.getContentProps()}>
    <div {...api.getDragTriggerProps()}>
      <div {...api.getHeaderProps()}>
        <p {...api.getTitleProps()}>Floating Panel</p>
        <div {...api.getControlProps()}>
          <button {...api.getStageTriggerProps({ stage: "minimized" })}>
            <Minus />
          </button>
          <button {...api.getStageTriggerProps({ stage: "maximized" })}>
            <Maximize2 />
          </button>
          <button {...api.getStageTriggerProps({ stage: "default" })}>
            <ArrowDownLeft />
          </button>
          <button {...api.getCloseTriggerProps()}>
            <XIcon />
          </button>
        </div>
      </div>
    </div>
    <div {...api.getBodyProps()}>
      <p>Some content</p>
    </div>

    <div {...api.getResizeTriggerProps({ axis: "n" })}></div>
    <div {...api.getResizeTriggerProps({ axis: "e" })}></div>
    <div {...api.getResizeTriggerProps({ axis: "w" })}></div>
    <div {...api.getResizeTriggerProps({ axis: "s" })}></div>
    <div {...api.getResizeTriggerProps({ axis: "ne" })}></div>
    <div {...api.getResizeTriggerProps({ axis: "se" })}></div>
    <div {...api.getResizeTriggerProps({ axis: "sw" })}></div>
    <div {...api.getResizeTriggerProps({ axis: "nw" })}></div>
  </div>
</div>
```

### Resizing

#### Setting the initial size

To set the initial size of the floating panel, you can pass the `defaultSize`
prop to the machine.

```tsx {2}
const service = useMachine(floatingPanel.machine, {
  defaultSize: { width: 300, height: 300 },
})
```

#### Controlling the size

To control the size of the floating panel programmatically, you can pass the
`size` `onResize` prop to the machine.

```tsx {2}
const service = useMachine(floatingPanel.machine, {
  size: { width: 300, height: 300 },
  onSizeChange(details) {
    // details => { width: number, height: number }
    console.log("floating panel is:", details.width, details.height)
  },
})
```

#### Disable resizing

By default, the panel can be resized by dragging its edges (resize handles). To
disable this behavior, set the `resizable` prop to `false`.

```tsx {2}
const service = useMachine(floatingPanel.machine, {
  resizable: false,
})
```

#### Setting size constraints

You can also control the minimum allowed dimensions of the panel by using the
`minSize` and `maxSize` props.

```tsx {2,3}
const service = useMachine(floatingPanel.machine, {
  minSize: { width: 100, height: 100 },
  maxSize: { width: 500, height: 500 },
})
```

### Aspect ratio

To lock the aspect ratio of the floating panel, set the `lockAspectRatio` prop.
This will ensure the panel maintains a consistent aspect ratio while being
resized.

```tsx {2}
const service = useMachine(floatingPanel.machine, {
  lockAspectRatio: true,
})
```

### Positioning

#### Setting the initial position

To specify the initial position of the floating panel, use the `defaultPosition`
prop. If `defaultPosition` is not provided, the floating panel will be initially
positioned at the center of the viewport.

```tsx {2}
const service = useMachine(floatingPanel.machine, {
  defaultPosition: { x: 500, y: 200 },
})
```

#### Anchor position

An alternative to setting the initial position is to provide a function that
returns the anchor position. This function is called when the panel is opened
and receives the `triggerRect` and `boundaryRect`.

```tsx {2}
const service = useMachine(floatingPanel.machine, {
  getAnchorPosition({ triggerRect, boundaryRect }) {
    return {
      x: boundaryRect.x + (boundaryRect.width - triggerRect.width) / 2,
      y: boundaryRect.y + (boundaryRect.height - triggerRect.height) / 2,
    }
  },
})
```

#### Controlling the position

To control the position of the floating panel programmatically, you can pass the
`position` and `onPositionChange` prop to the machine.

```tsx {2}
const service = useMachine(floatingPanel.machine, {
  position: { x: 500, y: 200 },
  onPositionChange(details) {
    // details => { x: number, y: number }
    console.log("floating panel is:", details.x, details.y)
  },
})
```

#### Disable dragging

The floating panel enables you to set its position and move it by dragging. To
disable this behavior, set the `draggable` prop to `false`.

### Events

The floating panel generates a variety of events that you can handle.

#### Open State

When the floating panel is `opened` or `closed`, the `onOpenChange` callback is
invoked.

```tsx {2-5}
const service = useMachine(floatingPanel.machine, {
  onOpenChange(details) {
    // details => { open: boolean }
    console.log("floating panel is:", details.open ? "opened" : "closed")
  },
})
```

#### Position Change

When the position of the floating panel changes, these callbacks are invoked:

- `onPositionChange` â When the position of the floating panel changes.
- `onPositionChangeEnd` â When the position of the floating panel changes ends.

```tsx {2-5}
const service = useMachine(floatingPanel.machine, {
  onPositionChange(details) {
    // details => { position: { x: number, y: number } }
    console.log("floating panel is:", details.position.x, details.position.y)
  },
  onPositionChangeEnd(details) {
    // details => { position: { x: number, y: number } }
    console.log("floating panel is:", details.position.x, details.position.y)
  },
})
```

#### Resize

When the size of the floating panel changes, these callbacks are invoked:

- `onResize` â When the size of the floating panel changes.
- `onResizeEnd` â When the size of the floating panel changes ends.

```tsx {2-5}
const service = useMachine(floatingPanel.machine, {
  onSizeChange(details) {
    // details => { size: { width: number, height: number } }
    console.log("floating panel is:", details.size.width, details.size.height)
  },
  onSizeChangeEnd(details) {
    // details => { size: { width: number, height: number } }
    console.log("floating panel is:", details.size.width, details.size.height)
  },
})
```

#### Minimizing and Maximizing

The floating panel can be minimized, default, and maximized by clicking the
respective buttons in the header. We refer to this as the panel's `stage`.

- When the panel is minimized, the body is hidden and the panel is resized to a
  minimum size.

- When the panel is maximized, the panel scales to the match the size of the
  defined boundary rect (via `getBoundaryEl` prop).

- When the panel is restored, the panel is resized back to the previously known
  size.

When the stage changes, the `onStageChange` callback is invoked.

```tsx {2-5}
const service = useMachine(floatingPanel.machine, {
  onStageChange(details) {
    // details => { stage: "minimized" | "maximized" | "default" }
    console.log("floating panel is:", details.stage)
  },
})
```

## Styling guide

The floating panel component uses data attributes to style its various parts.
Each part has a `data-scope="floating-panel"` and `data-part` attribute that you
can use to target specific elements.

```css
[data-scope="floating-panel"][data-part="content"] {
  /* Add styles for the main panel container */
}

[data-scope="floating-panel"][data-part="body"] {
  /* Add styles for the panel's content area */
}

[data-scope="floating-panel"][data-part="header"] {
  /* Add styles for the panel's header */
}

[data-scope="floating-panel"][data-part="stage-trigger"] {
  /* Add styles for state buttons in the header */
}

[data-scope="floating-panel"][data-part="resize-trigger"] {
  /* Add styles for resize handles */
}

/* North and south resize handles */
[data-scope="floating-panel"][data-part="resize-trigger"][data-axis="n"],
[data-scope="floating-panel"][data-part="resize-trigger"][data-axis="s"] {
  /* Add styles for north and south resize handles */
}

/* East and west resize handles */
[data-scope="floating-panel"][data-part="resize-trigger"][data-axis="e"],
[data-scope="floating-panel"][data-part="resize-trigger"][data-axis="w"] {
  /* Add styles for east and west resize handles */
}

/* Corner resize handles */
[data-scope="floating-panel"][data-part="resize-trigger"][data-axis="ne"],
[data-scope="floating-panel"][data-part="resize-trigger"][data-axis="nw"],
[data-scope="floating-panel"][data-part="resize-trigger"][data-axis="se"],
[data-scope="floating-panel"][data-part="resize-trigger"][data-axis="sw"] {
  /* Add styles for corner resize handles */
}
```

### Dragging

When dragging the panel, the `[data-dragging]` attribute is applied to the
panel.

```css
[data-scope="floating-panel"][data-part="content"][data-dragging] {
  /* Add styles for dragging state */
}
```

### Stacking

The floating panel has several states that can be targeted using data
attributes:

```css
/* When the panel is the topmost element */
[data-scope="floating-panel"][data-part="content"][data-topmost] {
  /* Add styles for topmost state */
}

/* When the panel is behind another panel */
[data-scope="floating-panel"][data-part="content"][data-behind] {
  /* Add styles for behind state */
}
```

## Methods and Properties

### Machine Context

The floating panel machine exposes the following context properties:

**`ids`**
Type: `Partial<{ trigger: string; positioner: string; content: string; title: string; header: string; }>`
Description: The ids of the elements in the floating panel. Useful for composition.

**`translations`**
Type: `IntlTranslations`
Description: The translations for the floating panel.

**`strategy`**
Type: `"absolute" | "fixed"`
Description: The strategy to use for positioning

**`allowOverflow`**
Type: `boolean`
Description: Whether the panel should be strictly contained within the boundary when dragging

**`open`**
Type: `boolean`
Description: The controlled open state of the panel

**`defaultOpen`**
Type: `boolean`
Description: The initial open state of the panel when rendered.
Use when you don't need to control the open state of the panel.

**`draggable`**
Type: `boolean`
Description: Whether the panel is draggable

**`resizable`**
Type: `boolean`
Description: Whether the panel is resizable

**`size`**
Type: `Size`
Description: The size of the panel

**`defaultSize`**
Type: `Size`
Description: The default size of the panel

**`minSize`**
Type: `Size`
Description: The minimum size of the panel

**`maxSize`**
Type: `Size`
Description: The maximum size of the panel

**`position`**
Type: `Point`
Description: The controlled position of the panel

**`defaultPosition`**
Type: `Point`
Description: The initial position of the panel when rendered.
Use when you don't need to control the position of the panel.

**`getAnchorPosition`**
Type: `(details: AnchorPositionDetails) => Point`
Description: Function that returns the initial position of the panel when it is opened.
If provided, will be used instead of the default position.

**`lockAspectRatio`**
Type: `boolean`
Description: Whether the panel is locked to its aspect ratio

**`closeOnEscape`**
Type: `boolean`
Description: Whether the panel should close when the escape key is pressed

**`getBoundaryEl`**
Type: `() => HTMLElement`
Description: The boundary of the panel. Useful for recalculating the boundary rect when
the it is resized.

**`disabled`**
Type: `boolean`
Description: Whether the panel is disabled

**`onPositionChange`**
Type: `(details: PositionChangeDetails) => void`
Description: Function called when the position of the panel changes via dragging

**`onPositionChangeEnd`**
Type: `(details: PositionChangeDetails) => void`
Description: Function called when the position of the panel changes via dragging ends

**`onOpenChange`**
Type: `(details: OpenChangeDetails) => void`
Description: Function called when the panel is opened or closed

**`onSizeChange`**
Type: `(details: SizeChangeDetails) => void`
Description: Function called when the size of the panel changes via resizing

**`onSizeChangeEnd`**
Type: `(details: SizeChangeDetails) => void`
Description: Function called when the size of the panel changes via resizing ends

**`persistRect`**
Type: `boolean`
Description: Whether the panel size and position should be preserved when it is closed

**`gridSize`**
Type: `number`
Description: The snap grid for the panel

**`onStageChange`**
Type: `(details: StageChangeDetails) => void`
Description: Function called when the stage of the panel changes

**`dir`**
Type: `"ltr" | "rtl"`
Description: The document's text/writing direction.

**`id`**
Type: `string`
Description: The unique identifier of the machine.

**`getRootNode`**
Type: `() => Node | ShadowRoot | Document`
Description: A root node to correctly resolve document in custom environments. E.x.: Iframes, Electron.

### Machine API

The floating panel `api` exposes the following methods:

**`open`**
Type: `boolean`
Description: Whether the panel is open

**`setOpen`**
Type: `(open: boolean) => void`
Description: Function to open or close the panel

**`dragging`**
Type: `boolean`
Description: Whether the panel is being dragged

**`resizing`**
Type: `boolean`
Description: Whether the panel is being resized

**`position`**
Type: `Point`
Description: The position of the panel

**`setPosition`**
Type: `(position: Point) => void`
Description: Function to set the position of the panel

**`size`**
Type: `Size`
Description: The size of the panel

**`setSize`**
Type: `(size: Size) => void`
Description: Function to set the size of the panel

**`minimize`**
Type: `VoidFunction`
Description: Function to minimize the panel

**`maximize`**
Type: `VoidFunction`
Description: Function to maximize the panel

**`restore`**
Type: `VoidFunction`
Description: Function to restore the panel before it was minimized or maximized

**`resizable`**
Type: `boolean`
Description: Whether the panel is resizable

**`draggable`**
Type: `boolean`
Description: Whether the panel is draggable

### Data Attributes

**`Trigger`**

**`data-scope`**: floating-panel
**`data-part`**: trigger
**`data-state`**: "open" | "closed"
**`data-dragging`**: Present when in the dragging state

**`Content`**

**`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

**`ResizeTrigger`**

**`data-scope`**: floating-panel
**`data-part`**: resize-trigger
**`data-disabled`**: Present when disabled
**`data-axis`**: The axis to resize

**`DragTrigger`**

**`data-scope`**: floating-panel
**`data-part`**: drag-trigger
**`data-disabled`**: Present when disabled

**`Control`**

**`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

**`Header`**

**`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

**`Body`**

**`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

### CSS Variables

<CssVarTable name="floating-panel" />
An hover card allows sighted users to preview content available behind a link

## Resources


[Latest version: v1.33.1](https://www.npmjs.com/package/@zag-js/hover-card)
[Logic Visualizer](https://zag-visualizer.vercel.app/hover-card)
[Source Code](https://github.com/chakra-ui/zag/tree/main/packages/machines/hover-card)



**Features**

- Customize side, alignment, offsets
- Optionally render a pointing arrow
- Supports custom open and close delays
- Opens on hover only
- Ignored by screen readers

## Installation

To use the hover card machine in your project, run the following command in your
command line:

```bash
npm install @zag-js/hover-card @zag-js/svelte