or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

default-rendering.mdheadless-rendering.mdindex.mdsingleton-mode.md

headless-rendering.mddocs/

0

# Headless Rendering

1

2

Headless rendering provides complete control over tooltip appearance and behavior through a custom render function. This approach is ideal for CSS-in-JS libraries, design systems, and when you need full control over the tooltip's DOM structure and styling.

3

4

## Capabilities

5

6

### Basic Headless Tooltip

7

8

Creates a tooltip using a custom render function instead of built-in rendering.

9

10

```typescript { .api }

11

/**

12

* Headless Tippy component imported from @tippyjs/react/headless

13

* @param props - TippyProps with render function

14

* @returns React component with custom tooltip rendering

15

*/

16

declare const Tippy: React.ForwardRefExoticComponent<TippyProps>;

17

18

interface TippyProps {

19

/** Custom render function for complete control over tooltip appearance */

20

render?: (

21

attrs: {

22

'data-placement': Placement;

23

'data-reference-hidden'?: string;

24

'data-escaped'?: string;

25

},

26

content?: React.ReactNode,

27

instance?: Instance

28

) => React.ReactNode;

29

/** Child element to attach tooltip to */

30

children?: React.ReactElement<any>;

31

/** Tooltip content passed to render function */

32

content?: React.ReactNode;

33

/** Other Tippy.js props for positioning and behavior */

34

[key: string]: any;

35

}

36

```

37

38

**Usage Examples:**

39

40

```typescript

41

import React from 'react';

42

import Tippy from '@tippyjs/react/headless';

43

44

// Basic headless tooltip

45

function BasicHeadless() {

46

return (

47

<Tippy

48

render={attrs => (

49

<div className="custom-tooltip" tabIndex={-1} {...attrs}>

50

My custom tooltip

51

</div>

52

)}

53

>

54

<button>Hover me</button>

55

</Tippy>

56

);

57

}

58

59

// With content prop

60

function HeadlessWithContent() {

61

return (

62

<Tippy

63

content="Dynamic content"

64

render={(attrs, content) => (

65

<div className="tooltip-box" tabIndex={-1} {...attrs}>

66

{content}

67

</div>

68

)}

69

>

70

<button>Hover me</button>

71

</Tippy>

72

);

73

}

74

```

75

76

### Render Function Attributes

77

78

The render function receives positioning and state attributes that should be applied to your custom element.

79

80

```typescript { .api }

81

interface RenderAttrs {

82

/** Current placement of the tooltip */

83

'data-placement': Placement;

84

/** Present when reference element is hidden */

85

'data-reference-hidden'?: string;

86

/** Present when tooltip has escaped its boundary */

87

'data-escaped'?: string;

88

}

89

```

90

91

**Usage Examples:**

92

93

```typescript

94

// Conditional styling based on attributes

95

function ConditionalStyling() {

96

return (

97

<Tippy

98

render={attrs => {

99

const isHidden = attrs['data-reference-hidden'] !== undefined;

100

const hasEscaped = attrs['data-escaped'] !== undefined;

101

102

return (

103

<div

104

className={`tooltip ${isHidden ? 'hidden' : ''} ${hasEscaped ? 'escaped' : ''}`}

105

tabIndex={-1}

106

{...attrs}

107

>

108

Conditional tooltip

109

</div>

110

);

111

}}

112

>

113

<button>Hover me</button>

114

</Tippy>

115

);

116

}

117

```

118

119

### CSS-in-JS Integration

120

121

Perfect integration with styled-components, emotion, and other CSS-in-JS libraries.

122

123

**Usage Examples:**

124

125

```typescript

126

import React from 'react';

127

import Tippy from '@tippyjs/react/headless';

128

import styled from 'styled-components';

129

130

const TooltipBox = styled.div`

131

background: #333;

132

color: white;

133

padding: 8px 12px;

134

border-radius: 4px;

135

font-size: 14px;

136

box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);

137

138

&[data-placement^='top'] {

139

margin-bottom: 8px;

140

}

141

142

&[data-placement^='bottom'] {

143

margin-top: 8px;

144

}

145

`;

146

147

function StyledTooltip() {

148

return (

149

<Tippy

150

render={(attrs, content) => (

151

<TooltipBox tabIndex={-1} {...attrs}>

152

{content}

153

</TooltipBox>

154

)}

155

content="Styled with CSS-in-JS"

156

>

157

<button>Styled tooltip</button>

158

</Tippy>

159

);

160

}

161

```

162

163

### Animation Libraries

164

165

Integration with Framer Motion, React Spring, and other animation libraries.

166

167

**Usage Examples:**

168

169

```typescript

170

import React from 'react';

171

import Tippy from '@tippyjs/react/headless';

172

import { motion } from 'framer-motion';

173

174

// Framer Motion animation

175

function AnimatedTooltip() {

176

return (

177

<Tippy

178

render={(attrs, content) => (

179

<motion.div

180

tabIndex={-1}

181

{...attrs}

182

initial={{ opacity: 0, scale: 0.8 }}

183

animate={{ opacity: 1, scale: 1 }}

184

exit={{ opacity: 0, scale: 0.8 }}

185

transition={{ duration: 0.2 }}

186

style={{

187

background: '#333',

188

color: 'white',

189

padding: '8px 12px',

190

borderRadius: '4px',

191

}}

192

>

193

{content}

194

</motion.div>

195

)}

196

content="Animated tooltip"

197

animation={false} // Disable built-in animation

198

>

199

<button>Animated tooltip</button>

200

</Tippy>

201

);

202

}

203

```

204

205

### Custom Arrow

206

207

Create custom arrows with proper positioning using Popper.js attributes.

208

209

```typescript { .api }

210

// Arrow must be an HTMLElement with data-popper-arrow attribute

211

```

212

213

**Usage Examples:**

214

215

```typescript

216

import React from 'react';

217

import Tippy from '@tippyjs/react/headless';

218

219

// CSS arrow with data-popper-arrow

220

function CustomArrowTooltip() {

221

return (

222

<Tippy

223

render={attrs => (

224

<div className="tooltip-with-arrow" tabIndex={-1} {...attrs}>

225

Custom tooltip content

226

<div data-popper-arrow className="arrow" />

227

</div>

228

)}

229

>

230

<button>Arrow tooltip</button>

231

</Tippy>

232

);

233

}

234

235

// Ref-based arrow positioning

236

function RefArrowTooltip() {

237

const [arrow, setArrow] = React.useState<HTMLDivElement | null>(null);

238

239

return (

240

<Tippy

241

render={attrs => (

242

<div className="tooltip" tabIndex={-1} {...attrs}>

243

Content

244

<div ref={setArrow} className="arrow" />

245

</div>

246

)}

247

popperOptions={{

248

modifiers: [

249

{

250

name: 'arrow',

251

options: {

252

element: arrow,

253

},

254

},

255

],

256

}}

257

>

258

<button>Ref arrow</button>

259

</Tippy>

260

);

261

}

262

```

263

264

### Instance Access

265

266

Access the Tippy instance for advanced control and method calls.

267

268

```typescript { .api }

269

interface RenderFunction {

270

(

271

attrs: RenderAttrs,

272

content?: React.ReactNode,

273

instance?: Instance

274

): React.ReactNode;

275

}

276

```

277

278

**Usage Examples:**

279

280

```typescript

281

// Instance methods and properties

282

function InstanceAccess() {

283

return (

284

<Tippy

285

render={(attrs, content, instance) => (

286

<div className="tooltip" tabIndex={-1} {...attrs}>

287

<div>{content}</div>

288

<button onClick={() => instance?.hide()}>

289

Close

290

</button>

291

</div>

292

)}

293

content="Tooltip with close button"

294

interactive={true}

295

>

296

<button>Interactive tooltip</button>

297

</Tippy>

298

);

299

}

300

```

301

302

### Design System Integration

303

304

Perfect for integrating with existing design systems and component libraries.

305

306

**Usage Examples:**

307

308

```typescript

309

import React from 'react';

310

import Tippy from '@tippyjs/react/headless';

311

import { Card, Text } from './design-system';

312

313

function DesignSystemTooltip() {

314

return (

315

<Tippy

316

render={(attrs, content) => (

317

<Card

318

elevation="high"

319

padding="sm"

320

tabIndex={-1}

321

{...attrs}

322

>

323

<Text size="sm">{content}</Text>

324

</Card>

325

)}

326

content="Design system tooltip"

327

>

328

<button>Design system</button>

329

</Tippy>

330

);

331

}

332

```

333

334

### Plugin Support

335

336

Headless rendering also supports Tippy.js plugins for extended functionality.

337

338

**Usage Examples:**

339

340

```typescript

341

import React from 'react';

342

import Tippy from '@tippyjs/react/headless';

343

import { followCursor } from 'tippy.js/headless'; // Note: import from headless

344

345

function HeadlessWithPlugin() {

346

return (

347

<Tippy

348

render={(attrs, content) => (

349

<div className="custom-tooltip" tabIndex={-1} {...attrs}>

350

{content}

351

</div>

352

)}

353

content="I follow the cursor!"

354

followCursor={true}

355

plugins={[followCursor]}

356

>

357

<button>Headless with plugin</button>

358

</Tippy>

359

);

360

}

361

```

362

363

Note: When using headless rendering, import plugins from `tippy.js/headless` instead of `tippy.js`.

364

365

## Import Path

366

367

Always import headless Tippy from the dedicated path:

368

369

```typescript

370

import Tippy from '@tippyjs/react/headless'; // Correct

371

import Tippy from '@tippyjs/react'; // Wrong - this is default rendering

372

```

373

374

## Key Considerations

375

376

- Always include `tabIndex={-1}` on your custom tooltip element for accessibility

377

- Spread the `attrs` object to ensure proper positioning and behavior

378

- The `className` prop doesn't work in headless mode - apply styles directly to your custom element

379

- Disable built-in animations with `animation={false}` when using custom animations

380

- For SVG arrows, wrap them in a `div` with the `data-popper-arrow` attribute