With Craftit Component
Problem
You are adding a positioned tooltip or popover to a Craftit custom element. The float's autoUpdate cleanup must be tied to the component's own disconnectedCallback so it does not outlive the element.
Solution
Usage inside a @vielzeug/craftit component with automatic autoUpdate cleanup.
ts
import { autoUpdate, computePosition, flip, offset, shift } from '@vielzeug/floatit';
import { define, onMount, signal } from '@vielzeug/craftit';
define('my-tooltip', {
setup({ host }) {
const visible = signal(false);
let tooltipEl: HTMLElement | null = null;
let cleanup: (() => void) | null = null;
function update() {
if (!tooltipEl) return;
const result = computePosition(host.el, tooltipEl, {
placement: 'top',
middleware: [offset(8), flip(), shift({ padding: 6 })],
});
tooltipEl.style.left = `${result.x}px`;
tooltipEl.style.top = `${result.y}px`;
}
onMount(() => {
host.el.addEventListener('mouseenter', () => {
visible.value = true;
cleanup = autoUpdate(host.el, tooltipEl!, update);
});
host.el.addEventListener('mouseleave', () => {
visible.value = false;
cleanup?.();
cleanup = null;
});
// Cleanup is run automatically on unmount by craftit
return () => cleanup?.();
});
},
});Pitfalls
autoUpdatemust be called after the Craftit element's shadow DOM is ready — insideonMounted, not the constructor. The floating element reference may not exist before that point.- Store the
autoUpdatecleanup function in a component property and call it indisconnectedCallback. Returning it fromonMountedis the cleanest pattern for Craftit. - The floating element must have
position: fixedorposition: absolute. Without explicit CSS positioning, the computedtop/leftvalues are applied but have no visual effect.