or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

docs

advanced-middleware.mdbasic-middleware.mdcore-positioning.mdindex.mdoverflow-detection.md
tile.json

overflow-detection.mddocs/

Overflow Detection

Utility for detecting element overflow within clipping boundaries, providing detailed information about how much an element overflows on each side.

Capabilities

Detect Overflow

Resolves with an object of overflow side offsets that determine how much the element is overflowing a given clipping boundary on each side.

/**
 * Resolves with an object of overflow side offsets that determine how much the
 * element is overflowing a given clipping boundary on each side.
 * - positive = overflowing the boundary by that number of pixels
 * - negative = how many pixels left before it will overflow  
 * - 0 = lies flush with the boundary
 * 
 * @param state - Current middleware state
 * @param options - Overflow detection configuration
 * @returns Promise resolving to side offsets
 */
function detectOverflow(
  state: MiddlewareState,
  options?: DetectOverflowOptions | ((state: MiddlewareState) => DetectOverflowOptions)
): Promise<SideObject>;

interface DetectOverflowOptions {
  /** The clipping element(s) or area in which overflow will be checked */
  boundary?: Boundary;
  /** The root clipping area in which overflow will be checked */
  rootBoundary?: RootBoundary;
  /** The element context to check overflow for */
  elementContext?: ElementContext;
  /** Whether to check overflow using alternate element's boundary */
  altBoundary?: boolean;
  /** Virtual padding for the resolved overflow detection offsets */
  padding?: Padding;
}

// Return type
type SideObject = {
  top: number;
  right: number;
  bottom: number;
  left: number;
};

// Configuration types
type Boundary = any; // Platform-specific boundary element or identifier
type RootBoundary = "viewport" | "document" | Rect;
type ElementContext = "reference" | "floating";
type Padding = number | Partial<SideObject>;

Usage Examples:

import { computePosition, detectOverflow } from "@floating-ui/core";

// Custom middleware using detectOverflow
const logOverflow = (): Middleware => ({
  name: "logOverflow",
  async fn(state) {
    const overflow = await detectOverflow(state);
    
    console.log("Overflow:", {
      top: overflow.top,      // Positive = overflowing top by N pixels
      right: overflow.right,  // Negative = N pixels before overflow  
      bottom: overflow.bottom,
      left: overflow.left
    });
    
    return {};
  }
});

// Use in positioning
await computePosition(reference, floating, {
  middleware: [logOverflow()],
  platform: domPlatform
});

Boundary Configuration

Control which clipping boundaries are used for overflow detection.

import { computePosition, detectOverflow } from "@floating-ui/core";

// Custom boundary detection
const customBoundaryMiddleware = (): Middleware => ({
  name: "customBoundary",
  async fn(state) {
    // Check overflow against viewport
    const viewportOverflow = await detectOverflow(state, {
      rootBoundary: "viewport"
    });
    
    // Check overflow against document  
    const documentOverflow = await detectOverflow(state, {
      rootBoundary: "document"
    });
    
    // Check overflow against custom element
    const containerElement = document.querySelector('.container');
    const containerOverflow = await detectOverflow(state, {
      boundary: containerElement
    });
    
    console.log("Viewport overflow:", viewportOverflow);
    console.log("Document overflow:", documentOverflow);
    console.log("Container overflow:", containerOverflow);
    
    return {};
  }
});

Element Context

Specify whether to check overflow for the reference or floating element.

import { computePosition, detectOverflow } from "@floating-ui/core";

// Check reference element visibility
const checkReferenceVisibility = (): Middleware => ({
  name: "checkReferenceVisibility",
  async fn(state) {
    // Check if reference element is overflowing/hidden
    const referenceOverflow = await detectOverflow(state, {
      elementContext: "reference",
      rootBoundary: "viewport"
    });
    
    const isReferenceHidden = Object.values(referenceOverflow)
      .some(side => side >= 0);
    
    if (isReferenceHidden) {
      console.log("Reference element is partially or fully hidden");
      return {
        data: { referenceHidden: true }
      };
    }
    
    return {};
  }
});

// Check floating element overflow
const checkFloatingOverflow = (): Middleware => ({
  name: "checkFloatingOverflow", 
  async fn(state) {
    // Check if floating element overflows
    const floatingOverflow = await detectOverflow(state, {
      elementContext: "floating",
      padding: 8 // Add 8px padding to boundaries
    });
    
    const overflowAmount = Math.max(
      floatingOverflow.top,
      floatingOverflow.right, 
      floatingOverflow.bottom,
      floatingOverflow.left
    );
    
    if (overflowAmount > 0) {
      console.log(`Floating element overflows by ${overflowAmount}px`);
    }
    
    return {};
  }
});

Padding Configuration

Add virtual padding to boundaries for overflow detection.

import { computePosition, detectOverflow } from "@floating-ui/core";

// Padding examples
const paddingMiddleware = (): Middleware => ({
  name: "paddingMiddleware",
  async fn(state) {
    // Uniform padding
    const overflow1 = await detectOverflow(state, {
      padding: 10 // 10px padding on all sides
    });
    
    // Different padding per side
    const overflow2 = await detectOverflow(state, {
      padding: { 
        top: 20,
        right: 15,
        bottom: 10,
        left: 5
      }
    });
    
    // Dynamic padding based on state using Derivable<Padding>
    const overflow3 = await detectOverflow(state, {
      padding: (state) => ({
        top: state.rects.floating.height * 0.1,
        right: 8,
        bottom: 8, 
        left: 8
      })
    });
    
    return {};
  }
});

Alternative Boundary

Use the opposite element's boundary for overflow detection.

import { computePosition, detectOverflow } from "@floating-ui/core";

// Alternative boundary usage
const altBoundaryMiddleware = (): Middleware => ({
  name: "altBoundaryMiddleware",
  async fn(state) {
    // Normal: Check floating element against boundary
    const normalOverflow = await detectOverflow(state, {
      elementContext: "floating",
      altBoundary: false
    });
    
    // Alternative: Check floating element against reference element's boundary
    const altOverflow = await detectOverflow(state, {
      elementContext: "floating", 
      altBoundary: true
    });
    
    console.log("Normal boundary overflow:", normalOverflow);
    console.log("Alternative boundary overflow:", altOverflow);
    
    return {};
  }
});

Common Patterns

Visibility Detection

import { computePosition, detectOverflow } from "@floating-ui/core";

// Check if element is fully visible
const isElementVisible = async (state: MiddlewareState): Promise<boolean> => {
  const overflow = await detectOverflow(state, {
    elementContext: "floating",
    rootBoundary: "viewport"
  });
  
  // Element is visible if no side is overflowing (all values <= 0)
  return Object.values(overflow).every(side => side <= 0);
};

// Visibility-aware middleware
const visibilityMiddleware = (): Middleware => ({
  name: "visibility",
  async fn(state) {
    const isVisible = await isElementVisible(state);
    
    return {
      data: { isVisible }
    };
  }
});

Smart Repositioning

import { computePosition, detectOverflow } from "@floating-ui/core";

// Reposition based on overflow
const smartReposition = (): Middleware => ({
  name: "smartReposition", 
  async fn(state) {
    const overflow = await detectOverflow(state);
    
    let { x, y } = state;
    
    // Adjust position based on overflow
    if (overflow.left > 0) {
      x += overflow.left; // Move right if overflowing left
    }
    if (overflow.right > 0) {
      x -= overflow.right; // Move left if overflowing right  
    }
    if (overflow.top > 0) {
      y += overflow.top; // Move down if overflowing top
    }
    if (overflow.bottom > 0) {
      y -= overflow.bottom; // Move up if overflowing bottom
    }
    
    return { x, y };
  }
});

Overflow Information

import { computePosition, detectOverflow } from "@floating-ui/core";

// Detailed overflow analysis
const analyzeOverflow = async (state: MiddlewareState) => {
  const overflow = await detectOverflow(state, {
    padding: 10
  });
  
  const analysis = {
    isOverflowing: Object.values(overflow).some(side => side > 0),
    overflowSides: Object.entries(overflow)
      .filter(([_, value]) => value > 0)
      .map(([side, value]) => ({ side, amount: value })),
    maxOverflow: Math.max(...Object.values(overflow)),
    totalOverflow: Object.values(overflow)
      .filter(value => value > 0)
      .reduce((sum, value) => sum + value, 0)
  };
  
  return analysis;
};

// Usage in middleware
const overflowAnalysisMiddleware = (): Middleware => ({
  name: "overflowAnalysis",
  async fn(state) {
    const analysis = await analyzeOverflow(state);
    
    console.log("Overflow analysis:", analysis);
    
    return {
      data: { overflowAnalysis: analysis }
    };
  }
});