Svelte 5 Runes powered wrapper for @floating-ui. An alternative approach to svelte-floating-ui which approx. does the same thing.
floating-runes will also:
autoPosition: false is provided)$state for .referenced, .tethered, .attached (tethered ?? referenced)portal actionOther than that, just use it as you would use @floating-ui🎉
Happy coding!🦒
Usage
Options and properties
bun add floating-runes
use:float - Designating the floating elementsuse:float.arrow - Designated arrow element; must be a direct child element of use:floatuse:float.ref - The thing the floated element(s) is referencingSvelte Playground - Usage example
<script>
    import floatingUI, { flip, shift, arrow } from 'floating-runes'
    const float = floatingUI({
        placement: 'top',
        middleware: [
            flip(),
            shift(),
            arrow()
        ]
    })
</script>
<div>
    <tooltip use:float>
        <arrow use:float.arrow></arrow>
    </tooltip>
    <button use:float.ref> Hover me </button>
</div>
[!TIP]
P.S. you can use multipleuse:floatfrom the same declaration.
You can use float.tether(element) to float to another element than the float.ref. Then use float.untether() and it returns to float.ref.
Svelte Playground - Tethering example
<script>
    import floatingUI, { flip, shift, arrow } from 'floating-runes'
    let url = '/a' // demo example
    const float = floatingUI()
</script>
{#snippet href(ref, text)}
     <a
        class:active={ref === url}
        use:float.ref={() => ref === url}
        use:float.tether={'pointerenter'}
        href={ref}
    >
        {text}
    </a>
{/snippet}
{#if float.tethered}
    <div class='hovered' use:float={{ untether: false }}></div>
{/if}
<div class='active' use:float={{ tether: false }}></div>
<div use:float.untether={'pointerleave'}>
    {@render href('/a', 'Hover me')}
    {@render href('/b', 'I want attention')}
    {@render href('/c', 'Guys... what about meeEeEe')}
    {@render href('/d', 'Ignore my brother')}
</div>
As per the documentation of @floating-ui, you can access the .then(...) which works in the same way as their documentation.
So you can go wild🦒
<script>
    import floatingUI, { ... } from 'floating-runes'
    const float = floatingUI({
        placement: 'top',
        middleware: [
            ...
        ]
    }).then(computedData => {
        const { middlewareData } = computedData
        ...
    })
</script>
As a bonus, you can use portal to move an element to another (such as the body).
When the component is destroyed, the element that was portalled, will naturally, also get destroyed.
<script>
    import { portal } from 'floating-runes'
</script>
<div use:portal> I'm in the body😏 </div>
<div use:portal={element}> I'm in another element </div>
FloatingRuneOptions extends ComputePositionConfig
| Property | Type | Description | 
|---|---|---|
| middleware? | Middleware[] | Array of middleware objects to modify the positioning or provide data for rendering | 
| platform? | Platform | Custom or extended platform object | 
| placement? | | 'top' | 'top-start' | 'top-end' | 'right' | 'right-start' | 'right-end' | 'bottom' | 'bottom-start' | 'bottom-end' | 'left' | 'left-start' | 'left-end' | Where to place the floating element relative to its reference element Default: 'bottom' | 
| strategy? | 'absolute' | 'fixed' | The type of CSS position property to use Default: absolute | 
| autoUpdate? | AutoUpdateOptions | Whether or not to auto-update the floating element's position | 
| autoPosition? | boolean | Whether or not to auto-position the floating element and the arrow, and auto-assign the position:to the strategy (absolute/fixed)Default: true | 
[!NOTE]
Thearrowmiddleware does not take anelementproperty. Instead apply the Svelte actionuse:float.arrow
.then(...)Read more aboutconst float = floatingUI(...).then((data: ComputePositionReturn) => void)
float.referenced, float.tethered and float.attachedThe element that has been referenced to, or tethered to. Attached will return tethered ?? referenced
use:float
This Svelte action creates a floater, that floats relative to the reference- and tethered element.
use:float={FloatOptions}
| Property | Type | Description | 
|---|---|---|
| tether | boolean | Whether-to-tether. Default: true | 
| untether | boolean | If falseit will stick to the last tethered target,instead of going back to the reference. Default: true | 
float.arrowuse:float.arrow
This Svelte action creates reference to the element that serves as the arrow to a use:float element. Must be a direct child.
<div use:float>
    ...
    <arrow use:float.arrow>...</arrow>
</div>
[!TIP]
Remember to include thearrowmiddleware, and put it after other middlewares if needed.
float.ref and float.tetheruse:float.ref and use:float.tether
These Svelte actions sets the reference point for the use:float element.
Additionally, they accept a trigger parameter: A conditional callback (() => boolean) or an event (keyof WindowEventMap).
Ex.
use:float.ref={() => url === href}
or
use:float.tether={'pointerenter'}
float.unref and float.untetherfloat.unref removes the current reference.
float.untether removes the tethering, so that the floating element will return to the reference (unless untether: false is provided).
Both can be used directly either via float.unref() / float.untether()
Or like float.ref and float.tether have a condition to trigger;
Ex.
use:float.untether={() => condition}
or
use:float.unref={'pointerleave'}