0
# Positioned Elements
1
2
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.
3
4
## Capabilities
5
6
### Popper Component
7
8
Creates positioned elements with advanced configuration options. Uses render props to provide positioning data, styles, and utility functions.
9
10
```typescript { .api }
11
/**
12
* Creates positioned popper element with comprehensive configuration
13
* @param children - Render prop function receiving positioning data and styles
14
* @param innerRef - Optional ref to the popper element for external access
15
* @param modifiers - Array of Popper.js modifiers for behavior customization
16
* @param placement - Preferred placement position relative to reference
17
* @param strategy - Positioning strategy (absolute or fixed)
18
* @param referenceElement - Override reference element (bypasses Manager context)
19
* @param onFirstUpdate - Callback fired after first positioning update
20
* @returns React element with positioned content
21
*/
22
function Popper<Modifiers>({
23
children,
24
innerRef,
25
modifiers,
26
placement,
27
strategy,
28
referenceElement,
29
onFirstUpdate,
30
}: PopperProps<Modifiers>): React.Node;
31
32
interface PopperProps<Modifiers> {
33
/** Render prop function that receives positioning data and controls */
34
children: (props: PopperChildrenProps) => React.ReactNode;
35
/** Optional ref for external access to the popper element */
36
innerRef?: React.Ref<any>;
37
/** Array of Popper.js modifiers for customizing behavior */
38
modifiers?: ReadonlyArray<Modifier<Modifiers>>;
39
/** Preferred placement position (default: 'bottom') */
40
placement?: PopperJS.Placement;
41
/** Positioning strategy - 'absolute' or 'fixed' (default: 'absolute') */
42
strategy?: PopperJS.PositioningStrategy;
43
/** Override reference element, bypassing Manager context */
44
referenceElement?: HTMLElement | PopperJS.VirtualElement;
45
/** Callback fired after first positioning update */
46
onFirstUpdate?: (state: Partial<PopperJS.State>) => void;
47
}
48
```
49
50
### Render Props Interface
51
52
The Popper component provides comprehensive positioning data through render props:
53
54
```typescript { .api }
55
interface PopperChildrenProps {
56
/** Ref that must be attached to the popper DOM element */
57
ref: React.Ref<any>;
58
/** Computed styles for positioning the popper element */
59
style: React.CSSProperties;
60
/** Final computed placement after auto-positioning */
61
placement: PopperJS.Placement;
62
/** Whether the reference element is hidden from view */
63
isReferenceHidden?: boolean;
64
/** Whether the popper has escaped its boundary constraints */
65
hasPopperEscaped?: boolean;
66
/** Async function to manually update popper positioning */
67
update: () => Promise<null | Partial<PopperJS.State>>;
68
/** Synchronous function to force immediate positioning update */
69
forceUpdate: () => Partial<PopperJS.State>;
70
/** Props and styling for arrow elements */
71
arrowProps: PopperArrowProps;
72
}
73
74
interface PopperArrowProps {
75
/** Ref for the arrow element */
76
ref: React.Ref<any>;
77
/** Computed styles for positioning the arrow */
78
style: React.CSSProperties;
79
}
80
```
81
82
**Usage Examples:**
83
84
```tsx
85
import React from "react";
86
import { Manager, Reference, Popper } from "react-popper";
87
88
// Basic popper with tooltip
89
function BasicTooltip() {
90
const [visible, setVisible] = React.useState(false);
91
92
return (
93
<Manager>
94
<Reference>
95
{({ ref }) => (
96
<button
97
ref={ref}
98
onMouseEnter={() => setVisible(true)}
99
onMouseLeave={() => setVisible(false)}
100
>
101
Hover for tooltip
102
</button>
103
)}
104
</Reference>
105
{visible && (
106
<Popper placement="top">
107
{({ ref, style, placement }) => (
108
<div
109
ref={ref}
110
style={{
111
...style,
112
background: "black",
113
color: "white",
114
padding: "4px 8px",
115
borderRadius: "4px",
116
}}
117
data-placement={placement}
118
>
119
Tooltip content
120
</div>
121
)}
122
</Popper>
123
)}
124
</Manager>
125
);
126
}
127
128
// Popper with arrow
129
function TooltipWithArrow() {
130
const [visible, setVisible] = React.useState(false);
131
132
return (
133
<Manager>
134
<Reference>
135
{({ ref }) => (
136
<button ref={ref} onClick={() => setVisible(!visible)}>
137
Toggle tooltip
138
</button>
139
)}
140
</Reference>
141
{visible && (
142
<Popper placement="top">
143
{({ ref, style, placement, arrowProps }) => (
144
<div
145
ref={ref}
146
style={{
147
...style,
148
background: "black",
149
color: "white",
150
padding: "8px",
151
borderRadius: "4px",
152
}}
153
data-placement={placement}
154
>
155
Tooltip with arrow
156
<div
157
ref={arrowProps.ref}
158
style={{
159
...arrowProps.style,
160
background: "black",
161
width: "8px",
162
height: "8px",
163
transform: "rotate(45deg)",
164
}}
165
/>
166
</div>
167
)}
168
</Popper>
169
)}
170
</Manager>
171
);
172
}
173
174
// Advanced popper with modifiers
175
function AdvancedPopper() {
176
const [visible, setVisible] = React.useState(false);
177
178
const modifiers = React.useMemo(
179
() => [
180
{
181
name: "offset",
182
options: {
183
offset: [0, 8], // 8px distance from reference
184
},
185
},
186
{
187
name: "preventOverflow",
188
options: {
189
padding: 8, // Keep 8px from viewport edges
190
},
191
},
192
],
193
[]
194
);
195
196
return (
197
<Manager>
198
<Reference>
199
{({ ref }) => (
200
<button ref={ref} onClick={() => setVisible(!visible)}>
201
Advanced positioning
202
</button>
203
)}
204
</Reference>
205
{visible && (
206
<Popper
207
placement="bottom-start"
208
modifiers={modifiers}
209
onFirstUpdate={(state) => {
210
console.log("Popper positioned:", state);
211
}}
212
>
213
{({ ref, style, placement, update, forceUpdate, isReferenceHidden, hasPopperEscaped }) => (
214
<div
215
ref={ref}
216
style={{
217
...style,
218
background: "white",
219
border: "1px solid #ccc",
220
borderRadius: "4px",
221
padding: "12px",
222
boxShadow: "0 2px 8px rgba(0,0,0,0.1)",
223
opacity: isReferenceHidden ? 0.5 : 1,
224
}}
225
data-placement={placement}
226
>
227
<div>Advanced tooltip content</div>
228
<div style={{ fontSize: "12px", color: "#666" }}>
229
Escaped: {hasPopperEscaped ? "Yes" : "No"}
230
</div>
231
<button onClick={() => update()}>Update Position</button>
232
<button onClick={() => { const state = forceUpdate(); console.log('Force updated:', state); }}>Force Update</button>
233
</div>
234
)}
235
</Popper>
236
)}
237
</Manager>
238
);
239
}
240
```
241
242
### Placement Options
243
244
The Popper component supports all Popper.js placement options:
245
246
```typescript { .api }
247
type Placement =
248
| "auto"
249
| "auto-start"
250
| "auto-end"
251
| "top"
252
| "top-start"
253
| "top-end"
254
| "bottom"
255
| "bottom-start"
256
| "bottom-end"
257
| "right"
258
| "right-start"
259
| "right-end"
260
| "left"
261
| "left-start"
262
| "left-end";
263
```
264
265
### Modifiers
266
267
Modifiers customize Popper behavior. Common built-in modifiers:
268
269
```typescript { .api }
270
// Common modifier configurations
271
type CommonModifiers =
272
| { name: "offset"; options: { offset: [number, number] } }
273
| { name: "preventOverflow"; options: { padding: number } }
274
| { name: "flip"; options: { fallbackPlacements: Placement[] } }
275
| { name: "arrow"; options: { element: HTMLElement } }
276
| { name: "hide"; enabled: boolean };
277
```
278
279
## Error Handling
280
281
The Popper component handles various edge cases:
282
283
- **Missing reference**: Gracefully handles cases where reference element is not available
284
- **Boundary constraints**: Respects viewport and container boundaries
285
- **Dynamic updates**: Automatically updates position when reference or popper elements change
286
- **Memory management**: Properly cleans up Popper instances on unmount
287
288
## Best Practices
289
290
1. **Always provide a ref to the popper element:**
291
```tsx
292
<Popper>
293
{({ ref, style }) => (
294
<div ref={ref} style={style}>Content</div>
295
)}
296
</Popper>
297
```
298
299
2. **Use the provided styles for positioning:**
300
```tsx
301
// ✅ Include provided styles
302
<div ref={ref} style={{ ...style, background: "white" }}>
303
304
// ❌ Don't ignore positioning styles
305
<div ref={ref} style={{ background: "white" }}>
306
```
307
308
3. **Handle arrow positioning correctly:**
309
```tsx
310
<Popper>
311
{({ ref, style, arrowProps }) => (
312
<div ref={ref} style={style}>
313
Content
314
<div ref={arrowProps.ref} style={arrowProps.style} />
315
</div>
316
)}
317
</Popper>
318
```
319
320
4. **Use modifiers for advanced positioning:**
321
```tsx
322
const modifiers = [
323
{ name: "offset", options: { offset: [0, 8] } },
324
{ name: "preventOverflow", options: { padding: 8 } }
325
];
326
<Popper modifiers={modifiers}>...</Popper>
327
```