or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

core-components.mdindex.mdperformance-optimization.mdplugin-system.mdreact-hooks.mdrender-functions.md

render-functions.mddocs/

0

# Render Functions

1

2

Customizable render functions for controlling how editor content is displayed. These functions provide complete control over the visual representation of editor content and are essential for creating custom editor UI.

3

4

## Capabilities

5

6

### Element Rendering

7

8

#### renderElement

9

10

Custom function for rendering Slate elements as React components.

11

12

```typescript { .api }

13

/**

14

* Custom element renderer props passed to renderElement

15

*/

16

interface RenderElementProps {

17

/** React children to render inside the element */

18

children: any;

19

/** The Slate element being rendered */

20

element: Element;

21

/** Required DOM attributes for proper Slate functionality */

22

attributes: {

23

'data-slate-node': 'element';

24

'data-slate-inline'?: true;

25

'data-slate-void'?: true;

26

dir?: 'rtl';

27

ref: any;

28

};

29

}

30

31

/**

32

* Type for custom element render function

33

* @param props - Render element props

34

* @returns JSX element representing the rendered element

35

*/

36

type RenderElementFunction = (props: RenderElementProps) => JSX.Element;

37

```

38

39

**Usage Example:**

40

41

```typescript

42

import React from 'react';

43

import { Editable, RenderElementProps } from 'slate-react';

44

45

const renderElement = ({ attributes, children, element }: RenderElementProps) => {

46

switch (element.type) {

47

case 'paragraph':

48

return <p {...attributes}>{children}</p>;

49

case 'heading-one':

50

return <h1 {...attributes}>{children}</h1>;

51

case 'heading-two':

52

return <h2 {...attributes}>{children}</h2>;

53

case 'block-quote':

54

return <blockquote {...attributes}>{children}</blockquote>;

55

case 'list-item':

56

return <li {...attributes}>{children}</li>;

57

case 'bulleted-list':

58

return <ul {...attributes}>{children}</ul>;

59

case 'numbered-list':

60

return <ol {...attributes}>{children}</ol>;

61

case 'link':

62

return (

63

<a {...attributes} href={element.url}>

64

{children}

65

</a>

66

);

67

default:

68

return <div {...attributes}>{children}</div>;

69

}

70

};

71

72

const MyEditor = () => (

73

<Editable renderElement={renderElement} />

74

);

75

```

76

77

### Leaf Rendering

78

79

#### renderLeaf

80

81

Custom function for rendering Slate text leaves with formatting.

82

83

```typescript { .api }

84

/**

85

* Custom leaf renderer props passed to renderLeaf

86

*/

87

interface RenderLeafProps {

88

/** React children to render inside the leaf */

89

children: any;

90

/** The Slate leaf being rendered (same as text) */

91

leaf: Text;

92

/** The Slate text node being rendered */

93

text: Text;

94

/** Required DOM attributes for proper Slate functionality */

95

attributes: {

96

'data-slate-leaf': true;

97

ref: any;

98

};

99

/** Position information for the leaf (optional) */

100

leafPosition?: LeafPosition;

101

}

102

103

/**

104

* Type for custom leaf render function

105

* @param props - Render leaf props

106

* @returns JSX element representing the rendered leaf

107

*/

108

type RenderLeafFunction = (props: RenderLeafProps) => JSX.Element;

109

```

110

111

**Usage Example:**

112

113

```typescript

114

import React from 'react';

115

import { Editable, RenderLeafProps } from 'slate-react';

116

117

const renderLeaf = ({ attributes, children, leaf }: RenderLeafProps) => {

118

if (leaf.bold) {

119

children = <strong>{children}</strong>;

120

}

121

122

if (leaf.italic) {

123

children = <em>{children}</em>;

124

}

125

126

if (leaf.underline) {

127

children = <u>{children}</u>;

128

}

129

130

if (leaf.strikethrough) {

131

children = <del>{children}</del>;

132

}

133

134

if (leaf.code) {

135

children = <code>{children}</code>;

136

}

137

138

if (leaf.highlight) {

139

children = (

140

<span style={{ backgroundColor: 'yellow' }}>

141

{children}

142

</span>

143

);

144

}

145

146

return <span {...attributes}>{children}</span>;

147

};

148

149

const MyEditor = () => (

150

<Editable renderLeaf={renderLeaf} />

151

);

152

```

153

154

### Text Rendering

155

156

#### renderText

157

158

Custom function for rendering individual text nodes. Rarely needed unless you need very specific text handling.

159

160

```typescript { .api }

161

/**

162

* Custom text renderer props passed to renderText

163

*/

164

interface RenderTextProps {

165

/** The Slate text node being rendered */

166

text: Text;

167

/** React children to render */

168

children: any;

169

/** Required DOM attributes for proper Slate functionality */

170

attributes: {

171

'data-slate-text': true;

172

ref: any;

173

};

174

}

175

176

/**

177

* Type for custom text render function

178

* @param props - Render text props

179

* @returns JSX element representing the rendered text

180

*/

181

type RenderTextFunction = (props: RenderTextProps) => JSX.Element;

182

```

183

184

**Usage Example:**

185

186

```typescript

187

import React from 'react';

188

import { Editable, RenderTextProps } from 'slate-react';

189

190

const renderText = ({ attributes, children, text }: RenderTextProps) => {

191

// Custom text processing - e.g., syntax highlighting

192

if (text.text.includes('TODO:')) {

193

return (

194

<span {...attributes} style={{ color: 'red', fontWeight: 'bold' }}>

195

{children}

196

</span>

197

);

198

}

199

200

return <span {...attributes}>{children}</span>;

201

};

202

203

const MyEditor = () => (

204

<Editable renderText={renderText} />

205

);

206

```

207

208

### Placeholder Rendering

209

210

#### renderPlaceholder

211

212

Custom function for rendering the editor placeholder when it's empty.

213

214

```typescript { .api }

215

/**

216

* Custom placeholder renderer props passed to renderPlaceholder

217

*/

218

interface RenderPlaceholderProps {

219

/** React children to render (the placeholder text) */

220

children: any;

221

/** Required DOM attributes for proper Slate functionality */

222

attributes: {

223

'data-slate-placeholder': boolean;

224

dir?: 'rtl';

225

contentEditable: boolean;

226

ref: React.RefCallback<any>;

227

style: React.CSSProperties;

228

};

229

}

230

231

/**

232

* Type for custom placeholder render function

233

* @param props - Render placeholder props

234

* @returns JSX element representing the rendered placeholder

235

*/

236

type RenderPlaceholderFunction = (props: RenderPlaceholderProps) => JSX.Element;

237

```

238

239

**Usage Example:**

240

241

```typescript

242

import React from 'react';

243

import { Editable, RenderPlaceholderProps } from 'slate-react';

244

245

const renderPlaceholder = ({ attributes, children }: RenderPlaceholderProps) => (

246

<div

247

{...attributes}

248

style={{

249

...attributes.style,

250

color: '#aaa',

251

fontStyle: 'italic',

252

fontSize: '14px'

253

}}

254

>

255

{children}

256

</div>

257

);

258

259

const MyEditor = () => (

260

<Editable

261

placeholder="Type something amazing..."

262

renderPlaceholder={renderPlaceholder}

263

/>

264

);

265

```

266

267

### Chunk Rendering (Performance)

268

269

#### renderChunk

270

271

Custom function for rendering chunks in performance-optimized scenarios with large documents.

272

273

```typescript { .api }

274

/**

275

* Custom chunk renderer props passed to renderChunk

276

*/

277

interface RenderChunkProps {

278

/** Whether this is the highest-level chunk */

279

highest: boolean;

280

/** Whether this is the lowest-level chunk */

281

lowest: boolean;

282

/** React children to render inside the chunk */

283

children: any;

284

/** Required DOM attributes for proper Slate functionality */

285

attributes: {

286

'data-slate-chunk': true;

287

ref: any;

288

};

289

}

290

291

/**

292

* Type for custom chunk render function

293

* @param props - Render chunk props

294

* @returns JSX element representing the rendered chunk

295

*/

296

type RenderChunkFunction = (props: RenderChunkProps) => JSX.Element;

297

```

298

299

**Usage Example:**

300

301

```typescript

302

import React from 'react';

303

import { Editable, RenderChunkProps } from 'slate-react';

304

305

const renderChunk = ({ attributes, children, highest, lowest }: RenderChunkProps) => {

306

// Apply different styling based on chunk level

307

const className = highest ? 'chunk-highest' : lowest ? 'chunk-lowest' : 'chunk-middle';

308

309

return (

310

<div {...attributes} className={className}>

311

{children}

312

</div>

313

);

314

};

315

316

const LargeDocumentEditor = () => (

317

<Editable renderChunk={renderChunk} />

318

);

319

```

320

321

## Advanced Rendering Patterns

322

323

### Conditional Rendering

324

325

Render different components based on element properties or editor state:

326

327

```typescript

328

import React from 'react';

329

import { useSelected, useFocused, RenderElementProps } from 'slate-react';

330

331

const ConditionalElement = ({ attributes, children, element }: RenderElementProps) => {

332

const selected = useSelected();

333

const focused = useFocused();

334

335

const isActive = selected && focused;

336

337

switch (element.type) {

338

case 'image':

339

return (

340

<div {...attributes}>

341

<img

342

src={element.url}

343

alt={element.alt}

344

style={{

345

border: isActive ? '2px solid blue' : 'none',

346

maxWidth: '100%'

347

}}

348

/>

349

{children}

350

</div>

351

);

352

case 'video':

353

return (

354

<div {...attributes}>

355

<video

356

src={element.url}

357

controls

358

style={{

359

border: isActive ? '2px solid blue' : 'none',

360

maxWidth: '100%'

361

}}

362

/>

363

{children}

364

</div>

365

);

366

default:

367

return <div {...attributes}>{children}</div>;

368

}

369

};

370

```

371

372

### Void Elements

373

374

Render void elements (elements that don't contain editable text):

375

376

```typescript

377

import React from 'react';

378

import { RenderElementProps } from 'slate-react';

379

380

const VoidElement = ({ attributes, children, element }: RenderElementProps) => {

381

switch (element.type) {

382

case 'image':

383

return (

384

<div {...attributes}>

385

<div contentEditable={false}>

386

<img src={element.url} alt={element.alt} />

387

</div>

388

{children}

389

</div>

390

);

391

case 'horizontal-rule':

392

return (

393

<div {...attributes}>

394

<div contentEditable={false}>

395

<hr />

396

</div>

397

{children}

398

</div>

399

);

400

default:

401

return <div {...attributes}>{children}</div>;

402

}

403

};

404

```

405

406

### Interactive Elements

407

408

Create interactive elements with event handlers:

409

410

```typescript

411

import React from 'react';

412

import { useSlateStatic, RenderElementProps } from 'slate-react';

413

import { Transforms } from 'slate';

414

415

const InteractiveElement = ({ attributes, children, element }: RenderElementProps) => {

416

const editor = useSlateStatic();

417

418

const handleButtonClick = () => {

419

const path = ReactEditor.findPath(editor, element);

420

Transforms.setNodes(

421

editor,

422

{ clicked: !element.clicked },

423

{ at: path }

424

);

425

};

426

427

if (element.type === 'button') {

428

return (

429

<div {...attributes}>

430

<button

431

contentEditable={false}

432

onClick={handleButtonClick}

433

style={{

434

backgroundColor: element.clicked ? 'green' : 'gray',

435

color: 'white',

436

border: 'none',

437

padding: '8px 16px',

438

cursor: 'pointer'

439

}}

440

>

441

{element.text || 'Click me'}

442

</button>

443

{children}

444

</div>

445

);

446

}

447

448

return <div {...attributes}>{children}</div>;

449

};

450

```

451

452

### Complex Leaf Formatting

453

454

Handle complex text formatting combinations:

455

456

```typescript

457

import React from 'react';

458

import { RenderLeafProps } from 'slate-react';

459

460

const ComplexLeaf = ({ attributes, children, leaf }: RenderLeafProps) => {

461

let element = children;

462

463

// Apply formatting in specific order

464

if (leaf.code) {

465

element = <code>{element}</code>;

466

}

467

468

if (leaf.bold) {

469

element = <strong>{element}</strong>;

470

}

471

472

if (leaf.italic) {

473

element = <em>{element}</em>;

474

}

475

476

if (leaf.underline) {

477

element = <u>{element}</u>;

478

}

479

480

if (leaf.strikethrough) {

481

element = <del>{element}</del>;

482

}

483

484

if (leaf.highlight) {

485

element = (

486

<span style={{ backgroundColor: leaf.highlightColor || 'yellow' }}>

487

{element}

488

</span>

489

);

490

}

491

492

if (leaf.fontSize) {

493

element = (

494

<span style={{ fontSize: `${leaf.fontSize}px` }}>

495

{element}

496

</span>

497

);

498

}

499

500

if (leaf.color) {

501

element = (

502

<span style={{ color: leaf.color }}>

503

{element}

504

</span>

505

);

506

}

507

508

return <span {...attributes}>{element}</span>;

509

};

510

```

511

512

## Render Function Best Practices

513

514

### Always Spread Attributes

515

516

Always spread the `attributes` prop on your root element:

517

518

```typescript

519

// ✅ Correct

520

const MyElement = ({ attributes, children }: RenderElementProps) => (

521

<div {...attributes}>{children}</div>

522

);

523

524

// ❌ Incorrect - missing attributes

525

const BadElement = ({ children }: RenderElementProps) => (

526

<div>{children}</div>

527

);

528

```

529

530

### Preserve Children

531

532

Always render the `children` prop:

533

534

```typescript

535

// ✅ Correct

536

const MyElement = ({ attributes, children }: RenderElementProps) => (

537

<div {...attributes}>

538

<h1>My Header</h1>

539

{children}

540

</div>

541

);

542

543

// ❌ Incorrect - missing children

544

const BadElement = ({ attributes }: RenderElementProps) => (

545

<div {...attributes}>

546

<h1>My Header</h1>

547

</div>

548

);

549

```

550

551

### Use contentEditable={false} for Non-Editable Areas

552

553

For void elements or interactive components:

554

555

```typescript

556

const ImageElement = ({ attributes, children, element }: RenderElementProps) => (

557

<div {...attributes}>

558

<div contentEditable={false}>

559

<img src={element.url} alt={element.alt} />

560

</div>

561

{children}

562

</div>

563

);

564

```