A client-side library to make absolutely positioned elements attach to elements in the page efficiently.
npx @tessl/cli install tessl/npm-tether@2.0.0Tether is a client-side JavaScript library for precise positioning of UI elements relative to each other on web pages. It solves complex positioning challenges that arise when DOM tree placement becomes problematic, such as handling fixed-positioned elements, scrollable containers, and viewport clipping issues.
npm install tetherimport Tether from "tether";For CommonJS:
const Tether = require("tether");For UMD/browser:
<script src="path/to/tether.min.js"></script>import Tether from "tether";
// Create a new tether instance
const tether = new Tether({
element: '.tooltip', // Element to be positioned
target: '.button', // Element to attach to
attachment: 'top center', // Attachment point on element
targetAttachment: 'bottom center' // Attachment point on target
});
// Enable positioning
tether.enable();
// Later, disable and clean up
tether.disable();
tether.destroy();Tether is built around several key components:
Essential positioning functionality for attaching elements to targets with precise control over attachment points and offsets.
class Tether {
constructor(options: TetherOptions);
}
interface TetherOptions {
element: string | HTMLElement;
target: string | HTMLElement;
attachment: string;
targetAttachment?: string;
offset?: string;
targetOffset?: string;
enabled?: boolean;
classPrefix?: string;
bodyElement?: HTMLElement;
}Event handling system for responding to positioning changes and tether lifecycle events.
// Event methods inherited from Evented base class
on(event: string, handler: Function, ctx?: any, once?: boolean): Tether;
once(event: string, handler: Function, ctx?: any): Tether;
off(event?: string, handler?: Function): Tether;
trigger(event: string, ...args: any[]): Tether;Advanced positioning constraints to keep elements within specified boundaries and handle viewport clipping.
interface ConstraintOptions {
to: string | HTMLElement | Array<number>;
attachment?: string;
pin?: boolean | string | Array<string>;
outOfBoundsClass?: string;
pinnedClass?: string;
}Performance optimizations and positioning strategies for smooth user experiences.
interface OptimizationOptions {
moveElement?: boolean;
allowPositionFixed?: boolean;
gpu?: boolean;
}Global Tether functionality and module system.
// Static properties
static modules: Array<PositioningModule>;
// Static methods
static position(): void;// Attachment point values
type AttachmentPoint =
| "top left" | "top center" | "top right"
| "middle left" | "middle center" | "middle right"
| "bottom left" | "bottom center" | "bottom right"
| "auto auto";
// Target modifier values
type TargetModifier = "visible" | "scroll-handle";
// Event names
type TetherEvents = "update" | "repositioned";
// Positioning module interface
interface PositioningModule {
initialize?: () => void;
position: (positionData: PositionData) => boolean | PositionCoordinates | void;
}
interface PositionData {
left: number;
top: number;
targetAttachment: AttachmentConfig;
targetPos: BoundsObject;
elementPos: BoundsObject;
offset: OffsetObject;
targetOffset: OffsetObject;
manualOffset: OffsetObject;
manualTargetOffset: OffsetObject;
scrollbarSize: { width: number; height: number };
attachment: AttachmentConfig;
}
interface PositionCoordinates {
top: number;
left: number;
}Tether automatically applies CSS classes to positioned elements and targets based on their state and positioning. All classes can be customized using the classPrefix option (default: 'tether') or overridden entirely with the classes option.
// Basic element classes
".tether-element" // Applied to the positioned element
".tether-target" // Applied to the target element
".tether-enabled" // Applied when tether is enabled
// Attachment classes (applied to both element and target)
".tether-element-attached-{side}" // Element attachment side
".tether-target-attached-{side}" // Target attachment side
// Where {side} can be: top, bottom, left, right, middle, center// Constraint-related classes
".tether-out-of-bounds" // Element is outside boundaries
".tether-out-of-bounds-{side}" // Specific boundary violation
".tether-pinned" // Element has been pinned
".tether-pinned-{side}" // Pinned to specific side
// Abutment classes (when using Abutment module)
".tether-abutted" // Element is abutting boundaries
".tether-abutted-{side}" // Abutting specific side
// Where {side} can be: top, bottom, left, right// Marker classes (for visual debugging)
".tether-element-marker" // Visual marker on positioned element
".tether-target-marker" // Visual marker on target element
".tether-marker-dot" // Dot within markers showing offset pointsOverride default classes using the classes option:
const tether = new Tether({
element: '.tooltip',
target: '.button',
attachment: 'top center',
targetAttachment: 'bottom center',
classes: {
'element': 'my-tooltip', // Instead of .tether-element
'target': 'my-trigger', // Instead of .tether-target
'enabled': false, // Disable .tether-enabled class
'out-of-bounds': 'tooltip-hidden' // Custom out-of-bounds class
}
});