0
# Portal and Layout
1
2
Portal rendering and overlay components for proper dialog layering, modal behavior, and visual presentation.
3
4
## Capabilities
5
6
### DialogPortal
7
8
Portal component that renders dialog content outside the normal DOM flow for proper layering and z-index management.
9
10
```typescript { .api }
11
/**
12
* Portal component that renders children outside normal DOM flow
13
* Ensures proper layering and avoids z-index conflicts
14
*/
15
type PortalProps = React.ComponentPropsWithoutRef<typeof PortalPrimitive>;
16
17
interface DialogPortalProps {
18
/** Content to be portaled */
19
children?: React.ReactNode;
20
/** Custom container element to portal into (defaults to document.body) */
21
container?: PortalProps['container'];
22
/** Force mounting when more control is needed for animations */
23
forceMount?: true;
24
}
25
26
const DialogPortal: React.FC<DialogPortalProps>;
27
```
28
29
**Usage Examples:**
30
31
```typescript
32
import {
33
Dialog,
34
DialogTrigger,
35
DialogPortal,
36
DialogContent
37
} from "@radix-ui/react-dialog";
38
39
// Basic portal usage
40
function BasicPortal() {
41
return (
42
<Dialog>
43
<DialogTrigger>Open</DialogTrigger>
44
<DialogPortal>
45
<DialogContent>
46
This content is rendered outside the normal DOM flow
47
</DialogContent>
48
</DialogPortal>
49
</Dialog>
50
);
51
}
52
53
// Custom portal container
54
function CustomContainer() {
55
const [container, setContainer] = React.useState<HTMLElement | null>(null);
56
57
return (
58
<div>
59
<div ref={setContainer} id="custom-portal-root" />
60
<Dialog>
61
<DialogTrigger>Open</DialogTrigger>
62
<DialogPortal container={container}>
63
<DialogContent>
64
This renders into the custom container
65
</DialogContent>
66
</DialogPortal>
67
</Dialog>
68
</div>
69
);
70
}
71
72
// Force mount for animations
73
function AnimatedPortal() {
74
const [open, setOpen] = React.useState(false);
75
76
return (
77
<Dialog open={open} onOpenChange={setOpen}>
78
<DialogTrigger>Open</DialogTrigger>
79
<DialogPortal forceMount>
80
<DialogContent className={open ? 'fade-in' : 'fade-out'}>
81
Always mounted for smooth animations
82
</DialogContent>
83
</DialogPortal>
84
</Dialog>
85
);
86
}
87
```
88
89
### DialogOverlay
90
91
Background overlay component that provides visual separation and modal behavior for dialogs.
92
93
```typescript { .api }
94
/**
95
* Background overlay component for modal dialogs
96
* Provides visual backdrop and handles scroll locking
97
* Only renders for modal dialogs (modal={true})
98
*/
99
type DialogOverlayElement = React.ComponentRef<typeof Primitive.div>;
100
interface DialogOverlayProps extends React.ComponentPropsWithoutRef<typeof Primitive.div> {
101
/** Force mounting when more control is needed for animations */
102
forceMount?: true;
103
}
104
105
const DialogOverlay: React.ForwardRefExoticComponent<
106
DialogOverlayProps & React.RefAttributes<DialogOverlayElement>
107
>;
108
```
109
110
**Usage Examples:**
111
112
```typescript
113
import {
114
Dialog,
115
DialogTrigger,
116
DialogPortal,
117
DialogOverlay,
118
DialogContent
119
} from "@radix-ui/react-dialog";
120
121
// Basic overlay usage
122
function BasicOverlay() {
123
return (
124
<Dialog>
125
<DialogTrigger>Open Modal</DialogTrigger>
126
<DialogPortal>
127
<DialogOverlay className="dialog-overlay" />
128
<DialogContent>
129
Modal content with overlay background
130
</DialogContent>
131
</DialogPortal>
132
</Dialog>
133
);
134
}
135
136
// Styled overlay
137
function StyledOverlay() {
138
return (
139
<Dialog>
140
<DialogTrigger>Open</DialogTrigger>
141
<DialogPortal>
142
<DialogOverlay
143
className="overlay"
144
style={{
145
backgroundColor: 'rgba(0, 0, 0, 0.75)',
146
backdropFilter: 'blur(4px)'
147
}}
148
/>
149
<DialogContent>Content here</DialogContent>
150
</DialogPortal>
151
</Dialog>
152
);
153
}
154
155
// Overlay with animation
156
function AnimatedOverlay() {
157
return (
158
<Dialog>
159
<DialogTrigger>Open</DialogTrigger>
160
<DialogPortal>
161
<DialogOverlay
162
forceMount
163
className="overlay-with-transition"
164
data-state={open ? 'open' : 'closed'}
165
/>
166
<DialogContent>Content here</DialogContent>
167
</DialogPortal>
168
</Dialog>
169
);
170
}
171
172
// No overlay for non-modal dialog
173
function NonModalDialog() {
174
return (
175
<Dialog modal={false}>
176
<DialogTrigger>Open Non-Modal</DialogTrigger>
177
<DialogPortal>
178
{/* DialogOverlay will not render when modal={false} */}
179
<DialogOverlay />
180
<DialogContent>
181
Non-modal content without blocking overlay
182
</DialogContent>
183
</DialogPortal>
184
</Dialog>
185
);
186
}
187
```
188
189
## Portal Behavior
190
191
### Default Portal Container
192
193
By default, DialogPortal renders content into `document.body`. This ensures:
194
195
- Content appears above other page elements
196
- Proper z-index stacking
197
- No overflow clipping from parent containers
198
- Accessibility tree structure is maintained
199
200
### Custom Portal Container
201
202
You can specify a custom container for special use cases:
203
204
```typescript
205
// Portal into a specific element
206
const portalRoot = document.getElementById('portal-root');
207
208
<DialogPortal container={portalRoot}>
209
<DialogContent>Custom container content</DialogContent>
210
</DialogPortal>
211
```
212
213
### Portal and React Context
214
215
Portal content maintains access to React context from its original location in the component tree, even though it renders elsewhere in the DOM.
216
217
## Overlay Behavior
218
219
### Modal Overlay Features
220
221
When `modal={true}` (default), DialogOverlay provides:
222
223
- **Visual Backdrop**: Semi-transparent background
224
- **Scroll Locking**: Prevents body scrolling when dialog is open
225
- **Click Outside**: Clicking overlay closes the dialog
226
- **Focus Management**: Helps contain focus within modal content
227
228
### Overlay Styling
229
230
The overlay renders as a `div` element with:
231
232
- `data-state` attribute ("open" or "closed")
233
- `pointer-events: auto` style to enable click handling
234
- Full viewport coverage positioning
235
236
```css
237
.dialog-overlay {
238
position: fixed;
239
inset: 0;
240
background-color: rgba(0, 0, 0, 0.5);
241
animation: fadeIn 150ms ease-out;
242
}
243
244
.dialog-overlay[data-state="closed"] {
245
animation: fadeOut 150ms ease-in;
246
}
247
```
248
249
### Overlay and Animation
250
251
Use `forceMount` to control overlay mounting for animations:
252
253
```typescript
254
// Overlay always mounted for smooth transitions
255
<DialogOverlay forceMount data-state={open ? 'open' : 'closed'} />
256
```
257
258
## Layout Patterns
259
260
### Standard Modal Layout
261
262
```typescript
263
<Dialog>
264
<DialogTrigger>Open</DialogTrigger>
265
<DialogPortal>
266
<DialogOverlay />
267
<DialogContent>
268
{/* Dialog content */}
269
</DialogContent>
270
</DialogPortal>
271
</Dialog>
272
```
273
274
### Non-Modal Layout
275
276
```typescript
277
<Dialog modal={false}>
278
<DialogTrigger>Open</DialogTrigger>
279
<DialogPortal>
280
{/* No overlay needed for non-modal */}
281
<DialogContent>
282
{/* Dialog content */}
283
</DialogContent>
284
</DialogPortal>
285
</Dialog>
286
```
287
288
### Custom Container Layout
289
290
```typescript
291
<div className="app-container">
292
<div id="dialog-portal" className="dialog-container" />
293
<Dialog>
294
<DialogTrigger>Open</DialogTrigger>
295
<DialogPortal container={document.getElementById('dialog-portal')}>
296
<DialogOverlay />
297
<DialogContent>
298
{/* Content portaled to custom container */}
299
</DialogContent>
300
</DialogPortal>
301
</Dialog>
302
</div>
303
```