or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

advanced-context.mdcontent-accessibility.mddialog-root.mdindex.mdportal-layout.mdtriggers-controls.md

portal-layout.mddocs/

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

```