- π§© Floating panel positioning with arrow and smart shifting
- β‘ Built on top of
@floating-ui/vue - π― Support for resize syncing and animated transitions
- π§ͺ Dual usage: composable or plug-and-play components
Created with β€οΈ by Stefano Biddau
sb-floating-panel-vue was designed to make it extremely easy to implement dropdowns, tooltips, and floating panels in Vue 3, without worrying about placement logic, arrow positioning, or responsive syncing. It wraps @floating-ui/vue into a more ergonomic composable or ready-to-use components.
# npm
npm install sb-floating-panel-vue
# yarn
yarn add sb-floating-panel-vue
# pnpm
pnpm add sb-floating-panel-vueUse the composable useSbFloatingPanel() for complete control.
| Option | Type | Required | Default | Description |
|---|---|---|---|---|
| placement | Placement |
Yes | β | Placement of the floating panel |
| strategy | 'absolute' | 'fixed' |
Yes | β | CSS positioning strategy |
| offsetValue | number |
Yes | β | Offset between reference and floating |
| hasArrow | boolean |
No | false |
Whether to render arrow |
| hasResize | boolean |
No | false |
Sync width of floating to reference |
| Property | Type | Description |
|---|---|---|
| reference | Ref<HTMLElement | null> |
Ref for the trigger element |
| floating | Ref<FloatingElement | null> |
Ref for the floating panel |
| floatingArrow | Ref<HTMLElement | null> |
Ref for the arrow element |
| floatingPlacement | Ref<Placement> |
The actual resolved placement |
| floatingStyle | ComputedRef<CSSProperties> |
Style for the floating panel |
| floatingArrowStyle | ComputedRef<CSSProperties> |
Style for the arrow |
| isOpen | Ref<boolean> |
Panel visibility |
| toggle / open / close | () => void |
Control methods to toggle visibility |
In your Vue component, you can use the composable like this:
In your script tag, import the composable and use it:
import { useSbFloatingPanel } from 'sb-floating-panel-vue';
const {
reference,
floating,
floatingArrow,
floatingStyle,
floatingArrowStyle,
isOpen,
toggle,
} = useSbFloatingPanel({
placement: 'bottom-start',
strategy: 'absolute',
offsetValue: 12,
hasArrow: true,
});In your template, you can bind the refs and styles:
<template>
<button ref="reference" @click="toggle()">Open Panel</button>
<div v-if="isOpen" ref="floating" :style="floatingStyle">
Panel
<div ref="floatingArrow" :style="floatingArrowStyle" />
</div>
</template>If you use components, you must import styles in main.ts:
import 'sb-floating-panel-vue/style.css';Wraps everything and provides the context.
| Prop | Type | Default | Description |
|---|---|---|---|
| placement | Placement |
'bottom-start' |
Placement of the floating panel relative to the reference element |
| strategy | 'absolute' | 'fixed' |
'absolute' |
CSS positioning strategy for the floating panel |
| offsetValue | number |
15 |
Offset in pixels between reference and floating panel |
| hasArrow | boolean |
false |
Whether to render an arrow pointing to the reference |
| hasResize | boolean |
false |
Whether the floating panel should sync its width with the reference |
Trigger element
| Prop | Type | Default | Description |
|---|---|---|---|
| referenceRef | Ref<HTMLElement | null> |
required | Reference element to which the floating panel is attached |
| as | 'button' | 'div' | 'span' | etc. |
'button' |
HTML tag to render. Defaults to <button> for accessibility |
| onClick | () => void |
β | Optional click handler, often used to toggle the floating panel visibility |
Floating panel
| Prop | Type | Default | Description |
|---|---|---|---|
| floatingRef | Ref<HTMLElement | null> |
required | The target element for the floating panel (popover, tooltip, etc.) |
| floatingArrowRef | Ref<HTMLElement | null> |
optional | The element used as the floating arrow |
| isOpen | boolean |
required | Controls visibility of the floating panel |
| floatingPlacement | Placement |
required | Current placement as resolved by @floating-ui/vue |
| floatingStyle | CSSProperties |
required | Inline style object applied to the floating panel |
| floatingArrowStyle | CSSProperties |
optional | Inline style object applied to the arrow element |
| arrowDimensions | number |
optional | Size (width/height) of the arrow in pixels |
| zIndex | number |
undefined |
Custom z-index applied to the floating and arrow elements |
| animation | 'fade' | 'scale-fade' | 'none' |
'scale-fade' |
Defines the animation style for enter/leave transitions |
| duration | number |
300 |
Duration in ms for the transition animations |
In your project, you can use the components like this:
In your script tag, import the components:
import { SbContainer, SbFloating, SbReference } from 'sb-floating-panel-vue';In your template, you can use the components as follows:
<SbContainer :has-arrow="true" strategy="fixed">
<template #default="{
reference,
floating,
floatingArrow,
floatingPlacement,
floatingStyle,
floatingArrowStyle,
isOpen,
toggle
}">
<SbReference :reference-ref="reference" :onClick="toggle">Toggle</SbReference>
<SbFloating
:is-open="isOpen.value"
:floating-ref="floating"
:floating-arrow-ref="floatingArrow"
:floating-placement="floatingPlacement.value"
:floating-style="floatingStyle.value"
:floating-arrow-style="floatingArrowStyle.value"
:arrow-dimensions="12"
:z-index="200"
>
Hello Panel!
</SbFloating>
</template>
</SbContainer>Due to <teleport> in <SbFloating>, if you apply custom directives directly to the component, Vue will warn:
[Vue warn]: Extraneous non-props attributes ([directive-name]) were passed to component but could not be automatically inherited because component renders fragment or text or teleport root nodes.
Solution: Move the directive to an inner element using the slot.
<SbFloating ...>
<div v-click-outside>...</div>
</SbFloating>