CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-react-popper

Official library to use Popper on React projects

Pending
Overview
Eval results
Files

positioned-elements.mddocs/

Positioned Elements

Positioned element creation functionality that renders elements with precise positioning relative to reference elements. The Popper component provides comprehensive configuration options and render props containing positioning data and styling.

Capabilities

Popper Component

Creates positioned elements with advanced configuration options. Uses render props to provide positioning data, styles, and utility functions.

/**
 * Creates positioned popper element with comprehensive configuration
 * @param children - Render prop function receiving positioning data and styles
 * @param innerRef - Optional ref to the popper element for external access
 * @param modifiers - Array of Popper.js modifiers for behavior customization
 * @param placement - Preferred placement position relative to reference
 * @param strategy - Positioning strategy (absolute or fixed)
 * @param referenceElement - Override reference element (bypasses Manager context)
 * @param onFirstUpdate - Callback fired after first positioning update
 * @returns React element with positioned content
 */
function Popper<Modifiers>({
  children,
  innerRef,
  modifiers,
  placement,
  strategy,
  referenceElement,
  onFirstUpdate,
}: PopperProps<Modifiers>): React.Node;

interface PopperProps<Modifiers> {
  /** Render prop function that receives positioning data and controls */
  children: (props: PopperChildrenProps) => React.ReactNode;
  /** Optional ref for external access to the popper element */
  innerRef?: React.Ref<any>;
  /** Array of Popper.js modifiers for customizing behavior */
  modifiers?: ReadonlyArray<Modifier<Modifiers>>;
  /** Preferred placement position (default: 'bottom') */
  placement?: PopperJS.Placement;
  /** Positioning strategy - 'absolute' or 'fixed' (default: 'absolute') */
  strategy?: PopperJS.PositioningStrategy;
  /** Override reference element, bypassing Manager context */
  referenceElement?: HTMLElement | PopperJS.VirtualElement;
  /** Callback fired after first positioning update */
  onFirstUpdate?: (state: Partial<PopperJS.State>) => void;
}

Render Props Interface

The Popper component provides comprehensive positioning data through render props:

interface PopperChildrenProps {
  /** Ref that must be attached to the popper DOM element */
  ref: React.Ref<any>;
  /** Computed styles for positioning the popper element */
  style: React.CSSProperties;
  /** Final computed placement after auto-positioning */
  placement: PopperJS.Placement;
  /** Whether the reference element is hidden from view */
  isReferenceHidden?: boolean;
  /** Whether the popper has escaped its boundary constraints */
  hasPopperEscaped?: boolean;
  /** Async function to manually update popper positioning */
  update: () => Promise<null | Partial<PopperJS.State>>;
  /** Synchronous function to force immediate positioning update */
  forceUpdate: () => Partial<PopperJS.State>;
  /** Props and styling for arrow elements */
  arrowProps: PopperArrowProps;
}

interface PopperArrowProps {
  /** Ref for the arrow element */
  ref: React.Ref<any>;
  /** Computed styles for positioning the arrow */
  style: React.CSSProperties;
}

Usage Examples:

import React from "react";
import { Manager, Reference, Popper } from "react-popper";

// Basic popper with tooltip
function BasicTooltip() {
  const [visible, setVisible] = React.useState(false);

  return (
    <Manager>
      <Reference>
        {({ ref }) => (
          <button
            ref={ref}
            onMouseEnter={() => setVisible(true)}
            onMouseLeave={() => setVisible(false)}
          >
            Hover for tooltip
          </button>
        )}
      </Reference>
      {visible && (
        <Popper placement="top">
          {({ ref, style, placement }) => (
            <div
              ref={ref}
              style={{
                ...style,
                background: "black",
                color: "white",
                padding: "4px 8px",
                borderRadius: "4px",
              }}
              data-placement={placement}
            >
              Tooltip content
            </div>
          )}
        </Popper>
      )}
    </Manager>
  );
}

// Popper with arrow
function TooltipWithArrow() {
  const [visible, setVisible] = React.useState(false);

  return (
    <Manager>
      <Reference>
        {({ ref }) => (
          <button ref={ref} onClick={() => setVisible(!visible)}>
            Toggle tooltip
          </button>
        )}
      </Reference>
      {visible && (
        <Popper placement="top">
          {({ ref, style, placement, arrowProps }) => (
            <div
              ref={ref}
              style={{
                ...style,
                background: "black",
                color: "white",
                padding: "8px",
                borderRadius: "4px",
              }}
              data-placement={placement}
            >
              Tooltip with arrow
              <div
                ref={arrowProps.ref}
                style={{
                  ...arrowProps.style,
                  background: "black",
                  width: "8px",
                  height: "8px",
                  transform: "rotate(45deg)",
                }}
              />
            </div>
          )}
        </Popper>
      )}
    </Manager>
  );
}

// Advanced popper with modifiers
function AdvancedPopper() {
  const [visible, setVisible] = React.useState(false);

  const modifiers = React.useMemo(
    () => [
      {
        name: "offset",
        options: {
          offset: [0, 8], // 8px distance from reference
        },
      },
      {
        name: "preventOverflow",
        options: {
          padding: 8, // Keep 8px from viewport edges
        },
      },
    ],
    []
  );

  return (
    <Manager>
      <Reference>
        {({ ref }) => (
          <button ref={ref} onClick={() => setVisible(!visible)}>
            Advanced positioning
          </button>
        )}
      </Reference>
      {visible && (
        <Popper
          placement="bottom-start"
          modifiers={modifiers}
          onFirstUpdate={(state) => {
            console.log("Popper positioned:", state);
          }}
        >
          {({ ref, style, placement, update, forceUpdate, isReferenceHidden, hasPopperEscaped }) => (
            <div
              ref={ref}
              style={{
                ...style,
                background: "white",
                border: "1px solid #ccc",
                borderRadius: "4px",
                padding: "12px",
                boxShadow: "0 2px 8px rgba(0,0,0,0.1)",
                opacity: isReferenceHidden ? 0.5 : 1,
              }}
              data-placement={placement}
            >
              <div>Advanced tooltip content</div>
              <div style={{ fontSize: "12px", color: "#666" }}>
                Escaped: {hasPopperEscaped ? "Yes" : "No"}
              </div>
              <button onClick={() => update()}>Update Position</button>
              <button onClick={() => { const state = forceUpdate(); console.log('Force updated:', state); }}>Force Update</button>
            </div>
          )}
        </Popper>
      )}
    </Manager>
  );
}

Placement Options

The Popper component supports all Popper.js placement options:

type Placement =
  | "auto"
  | "auto-start"
  | "auto-end"
  | "top"
  | "top-start" 
  | "top-end"
  | "bottom"
  | "bottom-start"
  | "bottom-end"
  | "right"
  | "right-start"
  | "right-end"
  | "left"
  | "left-start"
  | "left-end";

Modifiers

Modifiers customize Popper behavior. Common built-in modifiers:

// Common modifier configurations
type CommonModifiers = 
  | { name: "offset"; options: { offset: [number, number] } }
  | { name: "preventOverflow"; options: { padding: number } }
  | { name: "flip"; options: { fallbackPlacements: Placement[] } }
  | { name: "arrow"; options: { element: HTMLElement } }
  | { name: "hide"; enabled: boolean };

Error Handling

The Popper component handles various edge cases:

  • Missing reference: Gracefully handles cases where reference element is not available
  • Boundary constraints: Respects viewport and container boundaries
  • Dynamic updates: Automatically updates position when reference or popper elements change
  • Memory management: Properly cleans up Popper instances on unmount

Best Practices

  1. Always provide a ref to the popper element:

    <Popper>
      {({ ref, style }) => (
        <div ref={ref} style={style}>Content</div>
      )}
    </Popper>
  2. Use the provided styles for positioning:

    // ✅ Include provided styles
    <div ref={ref} style={{ ...style, background: "white" }}>
    
    // ❌ Don't ignore positioning styles
    <div ref={ref} style={{ background: "white" }}>
  3. Handle arrow positioning correctly:

    <Popper>
      {({ ref, style, arrowProps }) => (
        <div ref={ref} style={style}>
          Content
          <div ref={arrowProps.ref} style={arrowProps.style} />
        </div>
      )}
    </Popper>
  4. Use modifiers for advanced positioning:

    const modifiers = [
      { name: "offset", options: { offset: [0, 8] } },
      { name: "preventOverflow", options: { padding: 8 } }
    ];
    <Popper modifiers={modifiers}>...</Popper>

Install with Tessl CLI

npx tessl i tessl/npm-react-popper

docs

context-management.md

hook-interface.md

index.md

positioned-elements.md

reference-handling.md

tile.json