Skip to content
orbit logoOrbitUI
Zero-dependency floating element positioning for tooltips, dropdowns, menus, and popovers.
v0.0.14.7 KB gzip Browser · SSR
floatcomputePositioncomputePositionAsynccomputePositionRafautoUpdatedetectOverflowoffsetflip +9 more →

Why Orbit?

Positioning floating UI by hand quickly turns into repeated math for viewport boundaries, arrow offsets, and scroll/resize tracking.

FeatureOrbitFloating UIPopper
Bundle size4.7 KB~10 kB~6 kB
Middleware pipeline
Direct compute API
High-level follow APIPartial
Inline anchor middleware
Auto-update helpers
Framework agnostic
Zero dependencies

Use Orbit when you want a lightweight, DOM-first positioning engine with direct control and no framework adapter requirements.

Consider larger alternatives when you need their existing integration ecosystem or migration compatibility.

Installation

sh
pnpm add @vielzeug/orbit
sh
npm install @vielzeug/orbit
sh
yarn add @vielzeug/orbit

Quick Start

Use float() for the common case — it writes left/top and keeps the position in sync. It returns a FloatHandle; always call handle.dispose() on teardown.

ts
import { flip, float, offset, shift } from '@vielzeug/orbit';

const trigger = document.querySelector<HTMLElement>('#trigger')!;
const tooltip = document.querySelector<HTMLElement>('#tooltip')!;

const handle = float(trigger, tooltip, {
  placement: 'top',
  middleware: [offset(8), flip(), shift({ padding: 6 })],
});

// Call dispose when the tooltip is removed
handle.dispose();

Or use presets for ready-made middleware stacks:

ts
import { float } from '@vielzeug/orbit';
import { tooltip as tooltipPreset } from '@vielzeug/orbit/presets';

const handle = float(trigger, tooltip, tooltipPreset());
handle.dispose();

Features

  • float() covers the common position-and-follow case; returns a FloatHandle with dispose(), update(), and getPosition()
  • Custom apply(result) callback on float() for transforms or custom rendering
  • computePosition() returns x, y, placement, and middlewareData without touching the DOM
  • detectOverflow() returns per-side overflow offsets; used by built-in middleware and available for custom middleware
  • Global boundary and padding on computePosition() and float() — set once, all overflow-aware middleware inherit them
  • containingBlock option for position: absolute floating elements
  • Built-in middleware: offset, flip, autoPlacement, shift, size, arrow, hide
  • compose() — falsy-filter helper for building middleware arrays
  • limitShift() — constrains shift() drift to keep the float visually connected to its reference
  • inline middleware for multi-line inline references (now part of main entry)
  • Pre-configured presets (sub-path @vielzeug/orbit/presets): tooltip, dropdown, popover, contextMenu
  • autoUpdate() supports scroll, resize, ResizeObserver, visualViewport, animation frames, throttle, ancestor scroll containers, and pauseWhenHidden via IntersectionObserver
  • getSide() and getAlignment() utilities for reading placement components
  • floatWithAnchor() — CSS Anchor Positioning progressive enhancement (browser-native, no JS loop)
  • Reactive signal adapter (sub-path @vielzeug/orbit/reactive) — wraps float() with a @vielzeug/ripple signal
  • SSR-safe no-op stubs (sub-path @vielzeug/orbit/ssr)
  • Zero dependencies (optional peer: @vielzeug/ripple for the reactive sub-path)

Sub-paths

ImportPurpose
@vielzeug/orbitCore API, middleware (inline included), utilities, types
@vielzeug/orbit/presetsPre-configured middleware stacks
@vielzeug/orbit/reactiveReactive signal adapter (@vielzeug/ripple)
@vielzeug/orbit/devtoolsVisual debug overlay (development only)
@vielzeug/orbit/ssrNo-op stubs for server-side rendering

Documentation

See Also

  • Sigil — accessible web components that use Orbit internally for dropdown, tooltip, and popover positioning
  • Dnd — drag-and-drop engine; use Orbit to reposition drop targets and drag previews relative to containers
  • Craft — web-component authoring framework; Orbit integrates as a positioning primitive for overlay elements