- π§© 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>