Official library to use Popper on React projects
—
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.
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;
}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>
);
}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 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 };The Popper component handles various edge cases:
Always provide a ref to the popper element:
<Popper>
{({ ref, style }) => (
<div ref={ref} style={style}>Content</div>
)}
</Popper>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" }}>Handle arrow positioning correctly:
<Popper>
{({ ref, style, arrowProps }) => (
<div ref={ref} style={style}>
Content
<div ref={arrowProps.ref} style={arrowProps.style} />
</div>
)}
</Popper>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