or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

core-parser.mdindex.mdlinkify.mdrendering.mdrule-system.mdutilities.md

rendering.mddocs/

0

# Rendering System

1

2

The Remarkable rendering system converts parsed tokens into HTML output through a customizable rule-based renderer. Each token type has a corresponding rendering rule that can be modified or replaced.

3

4

## Capabilities

5

6

### Renderer Class

7

8

The main renderer class that converts tokens to HTML.

9

10

```javascript { .api }

11

/**

12

* HTML renderer with customizable rule-based output generation

13

*/

14

class Renderer {

15

/** Render tokens to HTML */

16

render(tokens: Token[], options: RemarkableOptions, env: object): string;

17

/** Render inline tokens to HTML */

18

renderInline(tokens: Token[], options: RemarkableOptions, env: object): string;

19

/** Collection of rendering rules */

20

rules: RendererRules;

21

/** Helper function for generating line breaks */

22

getBreak: (tokens: Token[], idx: number) => string;

23

}

24

25

interface RendererRules {

26

[ruleName: string]: RendererRule;

27

}

28

29

type RendererRule = (

30

tokens: Token[],

31

idx: number,

32

options: RemarkableOptions,

33

env: object,

34

renderer: Renderer

35

) => string;

36

```

37

38

**Usage Examples:**

39

40

```javascript

41

import { Remarkable } from "remarkable";

42

43

const md = new Remarkable();

44

45

// Access renderer

46

const renderer = md.renderer;

47

48

// Render tokens directly

49

const tokens = md.parse('# Hello World');

50

const html = renderer.render(tokens, md.options, {});

51

```

52

53

### Default Rendering Rules

54

55

Built-in rendering rules for all standard markdown elements.

56

57

```javascript { .api }

58

interface DefaultRenderingRules {

59

// Block elements

60

blockquote_open: RendererRule;

61

blockquote_close: RendererRule;

62

code: RendererRule;

63

fence: RendererRule;

64

heading_open: RendererRule;

65

heading_close: RendererRule;

66

hr: RendererRule;

67

list_item_open: RendererRule;

68

list_item_close: RendererRule;

69

ordered_list_open: RendererRule;

70

ordered_list_close: RendererRule;

71

bullet_list_open: RendererRule;

72

bullet_list_close: RendererRule;

73

paragraph_open: RendererRule;

74

paragraph_close: RendererRule;

75

76

// Inline elements

77

text: RendererRule;

78

code_inline: RendererRule;

79

em_open: RendererRule;

80

em_close: RendererRule;

81

strong_open: RendererRule;

82

strong_close: RendererRule;

83

del_open: RendererRule;

84

del_close: RendererRule;

85

ins_open: RendererRule;

86

ins_close: RendererRule;

87

mark_open: RendererRule;

88

mark_close: RendererRule;

89

sub: RendererRule;

90

sup: RendererRule;

91

92

// Links and images

93

link_open: RendererRule;

94

link_close: RendererRule;

95

image: RendererRule;

96

97

// Tables

98

table_open: RendererRule;

99

table_close: RendererRule;

100

thead_open: RendererRule;

101

thead_close: RendererRule;

102

tbody_open: RendererRule;

103

tbody_close: RendererRule;

104

tr_open: RendererRule;

105

tr_close: RendererRule;

106

th_open: RendererRule;

107

th_close: RendererRule;

108

td_open: RendererRule;

109

td_close: RendererRule;

110

111

// HTML

112

htmlblock: RendererRule;

113

htmltag: RendererRule;

114

115

// Special

116

softbreak: RendererRule;

117

hardbreak: RendererRule;

118

}

119

```

120

121

### Custom Rendering Rules

122

123

Modifying or replacing rendering rules for custom output.

124

125

```javascript { .api }

126

/**

127

* Signature for custom rendering rules

128

*/

129

type CustomRendererRule = (

130

tokens: Token[],

131

idx: number,

132

options: RemarkableOptions,

133

env: object,

134

renderer: Renderer

135

) => string;

136

```

137

138

**Usage Examples:**

139

140

```javascript

141

const md = new Remarkable();

142

143

// Custom heading rule with anchors

144

md.renderer.rules.heading_open = function(tokens, idx, options, env, renderer) {

145

const token = tokens[idx];

146

const level = token.hLevel;

147

const next = tokens[idx + 1];

148

149

// Generate ID from heading text

150

let id = '';

151

if (next && next.type === 'inline') {

152

id = next.content.toLowerCase().replace(/\s+/g, '-').replace(/[^\w-]/g, '');

153

}

154

155

return `<h${level} id="${id}">`;

156

};

157

158

// Custom code block with line numbers

159

md.renderer.rules.fence = function(tokens, idx, options, env, renderer) {

160

const token = tokens[idx];

161

const lang = token.info ? ` class="language-${token.info}"` : '';

162

const lines = token.content.split('\n');

163

164

let result = '<pre><code' + lang + '>\n';

165

lines.forEach((line, i) => {

166

result += `<span class="line-number">${i + 1}</span>${escapeHtml(line)}\n`;

167

});

168

result += '</code></pre>\n';

169

170

return result;

171

};

172

173

// Custom image rule with lazy loading

174

md.renderer.rules.image = function(tokens, idx, options, env, renderer) {

175

const token = tokens[idx];

176

const src = token.attrGet('src');

177

const alt = token.content;

178

const title = token.attrGet('title');

179

180

let result = '<img loading="lazy"';

181

result += ` src="${escapeHtml(src)}"`;

182

result += ` alt="${escapeHtml(alt)}"`;

183

if (title) {

184

result += ` title="${escapeHtml(title)}"`;

185

}

186

result += ' />';

187

188

return result;

189

};

190

```

191

192

### Token Structure

193

194

Understanding token structure for custom rendering rules.

195

196

```javascript { .api }

197

interface Token {

198

/** Token type (e.g., 'paragraph_open', 'text', 'strong_open') */

199

type: string;

200

/** HTML tag name for the token */

201

tag?: string;

202

/** HTML attributes as [name, value] pairs */

203

attrs?: Array<[string, string]>;

204

/** Source line mapping [start, end] */

205

map?: [number, number];

206

/** Nesting level change: 1 (open), -1 (close), 0 (self-close) */

207

nesting?: number;

208

/** Current nesting level */

209

level?: number;

210

/** Child tokens for container tokens */

211

children?: Token[];

212

/** Text content for text tokens */

213

content?: string;

214

/** Markup characters that created this token */

215

markup?: string;

216

/** Additional info (e.g., language for code blocks) */

217

info?: string;

218

/** Arbitrary metadata */

219

meta?: any;

220

/** True for block-level tokens */

221

block?: boolean;

222

/** True if token should not be rendered */

223

hidden?: boolean;

224

225

// Helper methods for token attributes

226

attrGet(name: string): string | null;

227

attrSet(name: string, value: string): void;

228

attrPush(attr: [string, string]): void;

229

attrJoin(name: string, value: string): void;

230

}

231

```

232

233

**Usage Examples:**

234

235

```javascript

236

// Working with token attributes

237

function customLinkRule(tokens, idx, options, env, renderer) {

238

const token = tokens[idx];

239

240

// Get existing attributes

241

const href = token.attrGet('href');

242

const title = token.attrGet('title');

243

244

// Modify attributes

245

if (href && href.startsWith('http')) {

246

token.attrSet('target', '_blank');

247

token.attrSet('rel', 'noopener noreferrer');

248

}

249

250

// Render with modified attributes

251

let result = '<a';

252

if (token.attrs) {

253

token.attrs.forEach(([name, value]) => {

254

result += ` ${name}="${escapeHtml(value)}"`;

255

});

256

}

257

result += '>';

258

259

return result;

260

}

261

```

262

263

### Output Customization

264

265

Advanced techniques for customizing HTML output.

266

267

```javascript { .api }

268

/**

269

* Helper function for generating line breaks after block elements

270

*/

271

function getBreak(tokens: Token[], idx: number): string;

272

```

273

274

**Usage Examples:**

275

276

```javascript

277

// Custom wrapper for all paragraphs

278

md.renderer.rules.paragraph_open = function(tokens, idx, options, env, renderer) {

279

return '<div class="paragraph-wrapper"><p>';

280

};

281

282

md.renderer.rules.paragraph_close = function(tokens, idx, options, env, renderer) {

283

return '</p></div>' + renderer.getBreak(tokens, idx);

284

};

285

286

// Add custom CSS classes based on content

287

md.renderer.rules.blockquote_open = function(tokens, idx, options, env, renderer) {

288

const token = tokens[idx];

289

let className = 'blockquote';

290

291

// Check if next tokens contain specific patterns

292

const nextTokens = tokens.slice(idx + 1);

293

const hasWarning = nextTokens.some(t =>

294

t.type === 'text' && t.content.toLowerCase().includes('warning')

295

);

296

297

if (hasWarning) {

298

className += ' warning';

299

}

300

301

return `<blockquote class="${className}">`;

302

};

303

304

// Custom table rendering with Bootstrap classes

305

md.renderer.rules.table_open = function() {

306

return '<div class="table-responsive"><table class="table table-striped">\n';

307

};

308

309

md.renderer.rules.table_close = function() {

310

return '</table></div>\n';

311

};

312

```

313

314

### Template Systems Integration

315

316

Integrating with template systems and frameworks.

317

318

**Usage Examples:**

319

320

```javascript

321

// React component integration

322

md.renderer.rules.image = function(tokens, idx, options, env, renderer) {

323

const token = tokens[idx];

324

const src = token.attrGet('src');

325

const alt = token.content;

326

327

// Return React component syntax

328

return `<ImageComponent src="${src}" alt="${alt}" />`;

329

};

330

331

// Vue component integration

332

md.renderer.rules.fence = function(tokens, idx, options, env, renderer) {

333

const token = tokens[idx];

334

const lang = token.info;

335

const code = token.content;

336

337

if (lang === 'vue-demo') {

338

return `<VueDemo code="${escapeForAttribute(code)}" />`;

339

}

340

341

// Fallback to default code rendering

342

return defaultFenceRule(tokens, idx, options, env, renderer);

343

};

344

```