Current section

Files

Jump to
mishka_chelekom usage-rules js floating.md
Raw

usage-rules/js/floating.md

# Floating Hook
JavaScript hook (`Floating`) for positioning floating elements like dropdowns, popovers, and tooltips.
## Used By
`dropdown`, `popover`, `tooltip`, `progress` (tooltip display)
## Data Attributes
| Attribute | Type | Default | Description |
|-----------|------|---------|-------------|
| `data-position` | `string` | `"bottom"` | Position relative to trigger: `top`, `bottom`, `left`, `right` |
| `data-floating-type` | `string` | `"dropdown"` | Type: `dropdown`, `popover`, `tooltip` |
| `data-clickable` | `string` | `"true"` | Open on click (vs hover) |
| `data-smart-position` | `string` | `"true"` | Auto-adjust to stay in viewport |
## Features
Smart positioning (stays within viewport) - multiple positions (top/bottom/left/right) - configurable click/hover triggers - closes on outside click - closes on Escape - focus management for accessibility - repositions on scroll.
## Element Structure
Expects a trigger and content element:
```html
<div id="dropdown-1" phx-hook="Floating" data-position="bottom" data-floating-type="dropdown">
<div data-floating-trigger="true" class="dropdown-trigger">
<button>Open Menu</button>
</div>
<div class="dropdown-content">
<a href="#">Option 1</a>
<a href="#">Option 2</a>
</div>
</div>
```
## Usage Examples
### Dropdown (default and with position)
```heex
<.dropdown id="user-menu">
<:trigger>
<.button>Menu</.button>
</:trigger>
<:content>
<.dropdown_item>Profile</.dropdown_item>
<.dropdown_item>Settings</.dropdown_item>
<.dropdown_divider />
<.dropdown_item>Logout</.dropdown_item>
</:content>
</.dropdown>
<.dropdown id="actions-menu" position="right">
<:trigger>
<.icon name="hero-ellipsis-vertical" class="size-5" />
</:trigger>
<:content>
<.dropdown_item>Edit</.dropdown_item>
<.dropdown_item>Delete</.dropdown_item>
</:content>
</.dropdown>
```
### Popover (default and clickable)
```heex
<.popover id="help-popover">
<:trigger>
<.icon name="hero-question-mark-circle" class="size-5 cursor-help" />
</:trigger>
<:content>
<h4 class="font-medium">Need Help?</h4>
<p class="text-sm text-gray-600">
Click here to learn more about this feature.
</p>
</:content>
</.popover>
<.popover id="info-popover" clickable={true}>
<:trigger>
<.button>Click for Info</.button>
</:trigger>
<:content>
<p>This popover opens on click.</p>
<.button size="small">Action</.button>
</:content>
</.popover>
```
### Tooltip (all positions)
```heex
<.tooltip>
<:trigger>
<.button>Hover me</.button>
</:trigger>
<:content>Helpful tooltip text</:content>
</.tooltip>
<.tooltip position="top">
<:trigger><span>Top</span></:trigger>
<:content>Top tooltip</:content>
</.tooltip>
<.tooltip position="bottom">
<:trigger><span>Bottom</span></:trigger>
<:content>Bottom tooltip</:content>
</.tooltip>
<.tooltip position="left">
<:trigger><span>Left</span></:trigger>
<:content>Left tooltip</:content>
</.tooltip>
<.tooltip position="right">
<:trigger><span>Right</span></:trigger>
<:content>Right tooltip</:content>
</.tooltip>
```
### Smart Positioning Disabled
```heex
<.dropdown id="fixed-dropdown" smart_position={false} position="bottom">
<:trigger>
<.button>Fixed Position</.button>
</:trigger>
<:content>
<p>Always shows below, even if clipped.</p>
</:content>
</.dropdown>
```
## CSS Classes
| Class | Description |
|-------|-------------|
| `.dropdown-trigger` | Trigger element container |
| `.dropdown-content` | Floating content container |
| `.show-dropdown` | Applied when visible |
| `.popover-trigger` | Popover trigger |
| `.popover-content` | Popover content |
| `.show-popover` | Popover visible state |
## Behavior by Type
| Type | Opens on | Closes on | Notes |
|------|----------|-----------|-------|
| Dropdown | click | outside click, Escape, item selection | |
| Popover | click (default) | outside click, Escape | stays open for interaction |
| Tooltip | hover, focus | mouse leave | no click interaction needed |
## Keyboard Controls
| Key | Action |
|-----|--------|
| `Escape` | Close floating element |
| `Tab` | Navigate focusable items |
| `Enter` | Activate trigger/item |
## JavaScript Integration
Register the hook in your `app.js`:
```javascript
import Floating from "./floating"
let liveSocket = new LiveSocket("/live", Socket, {
hooks: { Floating }
})
```