or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

arrow.mdindex.mdportal-content.mdprovider.mdtooltip-root.mdtrigger.mdutilities.md

portal-content.mddocs/

0

# Portal Rendering and Content Display

1

2

The `TooltipPortal` and `TooltipContent` components work together to render tooltip content outside the normal DOM hierarchy with sophisticated positioning, collision detection, and accessibility features.

3

4

## Capabilities

5

6

### TooltipPortal Component

7

8

Portal component that renders children in a different part of the DOM, typically at the document body level.

9

10

```typescript { .api }

11

/**

12

* Portal component for rendering tooltip content outside normal DOM flow

13

* @param children - Content to portal (typically TooltipContent)

14

* @param container - Container element to portal into (default: document.body)

15

* @param forceMount - Force mounting when controlling animation externally

16

*/

17

interface TooltipPortalProps {

18

children?: React.ReactNode;

19

container?: HTMLElement;

20

forceMount?: true;

21

}

22

23

const TooltipPortal: React.FC<TooltipPortalProps>;

24

```

25

26

### TooltipContent Component

27

28

Main tooltip content component with positioning, collision detection, and accessibility features.

29

30

```typescript { .api }

31

/**

32

* Main tooltip content component with positioning and accessibility

33

* @param children - Content to display in tooltip

34

* @param side - Preferred side relative to trigger

35

* @param sideOffset - Distance in pixels from trigger

36

* @param align - Alignment relative to trigger

37

* @param alignOffset - Offset in pixels along alignment axis

38

* @param avoidCollisions - Whether to avoid viewport collisions

39

* @param collisionBoundary - Boundary elements for collision detection

40

* @param collisionPadding - Padding around collision boundary

41

* @param arrowPadding - Minimum distance between arrow and content edges

42

* @param sticky - Sticky behavior when trigger moves

43

* @param hideWhenDetached - Hide when trigger is no longer visible

44

* @param aria-label - Accessible label for tooltip

45

* @param onEscapeKeyDown - Handler for escape key

46

* @param onPointerDownOutside - Handler for outside pointer events

47

* @param forceMount - Force mounting for animation control

48

*/

49

type TooltipContentElement = React.ComponentRef<"div">;

50

interface TooltipContentProps extends React.ComponentPropsWithoutRef<"div"> {

51

side?: "top" | "right" | "bottom" | "left";

52

sideOffset?: number;

53

align?: "start" | "center" | "end";

54

alignOffset?: number;

55

avoidCollisions?: boolean;

56

collisionBoundary?: Element | Element[];

57

collisionPadding?: number | Partial<Record<"top" | "right" | "bottom" | "left", number>>;

58

arrowPadding?: number;

59

sticky?: "partial" | "always";

60

hideWhenDetached?: boolean;

61

'aria-label'?: string;

62

onEscapeKeyDown?: (event: KeyboardEvent) => void;

63

onPointerDownOutside?: (event: CustomEvent) => void;

64

forceMount?: true;

65

}

66

67

const TooltipContent: React.forwardRef<TooltipContentElement, TooltipContentProps>;

68

```

69

70

**Usage Examples:**

71

72

```typescript

73

import {

74

TooltipProvider,

75

Tooltip,

76

TooltipTrigger,

77

TooltipPortal,

78

TooltipContent,

79

TooltipArrow

80

} from "@radix-ui/react-tooltip";

81

82

// Basic portal and content

83

function BasicTooltip() {

84

return (

85

<TooltipProvider>

86

<Tooltip>

87

<TooltipTrigger>Hover me</TooltipTrigger>

88

<TooltipPortal>

89

<TooltipContent>

90

Simple tooltip content

91

</TooltipContent>

92

</TooltipPortal>

93

</Tooltip>

94

</TooltipProvider>

95

);

96

}

97

98

// Custom positioning

99

function PositionedTooltip() {

100

return (

101

<TooltipProvider>

102

<Tooltip>

103

<TooltipTrigger>Hover me</TooltipTrigger>

104

<TooltipPortal>

105

<TooltipContent

106

side="right"

107

align="start"

108

sideOffset={10}

109

alignOffset={5}

110

>

111

Positioned tooltip

112

<TooltipArrow />

113

</TooltipContent>

114

</TooltipPortal>

115

</Tooltip>

116

</TooltipProvider>

117

);

118

}

119

120

// Collision avoidance

121

function SmartTooltip() {

122

return (

123

<TooltipProvider>

124

<Tooltip>

125

<TooltipTrigger>Near edge</TooltipTrigger>

126

<TooltipPortal>

127

<TooltipContent

128

side="top"

129

avoidCollisions={true}

130

collisionPadding={10}

131

>

132

This tooltip avoids viewport edges

133

</TooltipContent>

134

</TooltipPortal>

135

</Tooltip>

136

</TooltipProvider>

137

);

138

}

139

140

// Custom portal container

141

function CustomPortalTooltip() {

142

const containerRef = useRef<HTMLDivElement>(null);

143

144

return (

145

<div>

146

<div ref={containerRef} className="custom-portal-container" />

147

<TooltipProvider>

148

<Tooltip>

149

<TooltipTrigger>Hover me</TooltipTrigger>

150

<TooltipPortal container={containerRef.current}>

151

<TooltipContent>

152

Rendered in custom container

153

</TooltipContent>

154

</TooltipPortal>

155

</Tooltip>

156

</TooltipProvider>

157

</div>

158

);

159

}

160

161

// Rich content tooltip

162

function RichContentTooltip() {

163

return (

164

<TooltipProvider>

165

<Tooltip>

166

<TooltipTrigger>Product info</TooltipTrigger>

167

<TooltipPortal>

168

<TooltipContent className="rich-tooltip">

169

<div>

170

<h3>Product Details</h3>

171

<p>Price: $29.99</p>

172

<p>In stock: 15 items</p>

173

</div>

174

<TooltipArrow />

175

</TooltipContent>

176

</TooltipPortal>

177

</Tooltip>

178

</TooltipProvider>

179

);

180

}

181

```

182

183

### Portal Props

184

185

#### container

186

187

Specifies container element for portal rendering.

188

189

- **Type**: `HTMLElement`

190

- **Default**: `document.body`

191

- **Description**: Element to render portal content into

192

193

#### forceMount

194

195

Forces mounting regardless of open state for animation control.

196

197

- **Type**: `true`

198

- **Description**: Keeps content mounted for external animation libraries

199

200

### Content Props

201

202

#### Positioning Props

203

204

**side**: Preferred side relative to trigger

205

- **Type**: `"top" | "right" | "bottom" | "left"`

206

- **Default**: `"top"`

207

208

**sideOffset**: Distance from trigger

209

- **Type**: `number`

210

- **Default**: `0`

211

212

**align**: Alignment relative to trigger

213

- **Type**: `"start" | "center" | "end"`

214

- **Default**: `"center"`

215

216

**alignOffset**: Offset along alignment axis

217

- **Type**: `number`

218

- **Default**: `0`

219

220

#### Collision Detection Props

221

222

**avoidCollisions**: Enable collision detection

223

- **Type**: `boolean`

224

- **Default**: `true`

225

226

**collisionBoundary**: Elements to consider for collisions

227

- **Type**: `Element | Element[]`

228

- **Default**: Viewport boundaries

229

230

**collisionPadding**: Padding around collision boundary

231

- **Type**: `number | Partial<Record<"top" | "right" | "bottom" | "left", number>>`

232

- **Default**: `0`

233

234

#### Arrow Props

235

236

**arrowPadding**: Minimum distance between arrow and content edges

237

- **Type**: `number`

238

- **Default**: `0`

239

240

#### Behavior Props

241

242

**sticky**: Sticky behavior when trigger moves

243

- **Type**: `"partial" | "always"`

244

- **Default**: `"partial"`

245

246

**hideWhenDetached**: Hide when trigger is no longer visible

247

- **Type**: `boolean`

248

- **Default**: `false`

249

250

#### Accessibility Props

251

252

**aria-label**: Accessible label

253

- **Type**: `string`

254

- **Description**: Descriptive label for screen readers

255

256

#### Event Props

257

258

**onEscapeKeyDown**: Escape key handler

259

- **Type**: `(event: KeyboardEvent) => void`

260

261

**onPointerDownOutside**: Outside click handler

262

- **Type**: `(event: CustomEvent) => void`

263

264

### Content Features

265

266

#### Grace Area Hover

267

268

Content supports sophisticated hover behavior with grace areas:

269

- Pointer can move from trigger to content without closing

270

- Grace area calculations prevent accidental closing

271

- Smooth user experience when interacting with rich content

272

273

#### CSS Custom Properties

274

275

Content exposes positioning data via CSS custom properties:

276

- `--radix-tooltip-content-transform-origin`

277

- `--radix-tooltip-content-available-width`

278

- `--radix-tooltip-content-available-height`

279

- `--radix-tooltip-trigger-width`

280

- `--radix-tooltip-trigger-height`

281

282

#### Data Attributes

283

284

Content element receives data attributes for styling:

285

- `data-state`: `"closed" | "delayed-open" | "instant-open"`

286

- `data-side`: Current side placement

287

- `data-align`: Current alignment

288

289

### Portal and Content Aliases

290

291

```typescript { .api }

292

const Portal: React.FC<TooltipPortalProps>;

293

const Content: React.forwardRef<TooltipContentElement, TooltipContentProps>;

294

```

295

296

The `Portal` and `Content` components are aliases for shorter import names.

297

298

## Types

299

300

```typescript { .api }

301

type TooltipPortalProps = {

302

children?: React.ReactNode;

303

container?: HTMLElement;

304

forceMount?: true;

305

};

306

307

type TooltipContentElement = React.ComponentRef<"div">;

308

309

type TooltipContentProps = React.ComponentPropsWithoutRef<"div"> & {

310

side?: "top" | "right" | "bottom" | "left";

311

sideOffset?: number;

312

align?: "start" | "center" | "end";

313

alignOffset?: number;

314

avoidCollisions?: boolean;

315

collisionBoundary?: Element | Element[];

316

collisionPadding?: number | Partial<Record<"top" | "right" | "bottom" | "left", number>>;

317

arrowPadding?: number;

318

sticky?: "partial" | "always";

319

hideWhenDetached?: boolean;

320

'aria-label'?: string;

321

onEscapeKeyDown?: (event: KeyboardEvent) => void;

322

onPointerDownOutside?: (event: CustomEvent) => void;

323

forceMount?: true;

324

};

325

```