or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

tessl/npm-rehype-react

rehype plugin to transform HTML into JSX elements for React, Preact, Solid, Svelte, Vue and other frameworks

Workspace
tessl
Visibility
Public
Created
Last updated
Describes
npmpkg:npm/rehype-react@8.0.x

To install, run

npx @tessl/cli install tessl/npm-rehype-react@8.0.0

0

# rehype-react

1

2

rehype-react is a unified/rehype plugin that transforms HTML (hast syntax trees) into JSX elements compatible with multiple JavaScript frameworks including React, Preact, Solid, Svelte, and Vue. It serves as a bridge between HTML content and component-based applications, enabling developers to render HTML structures as JSX components with framework-specific optimizations.

3

4

## Package Information

5

6

- **Package Name**: rehype-react

7

- **Package Type**: npm

8

- **Language**: JavaScript/TypeScript (ESM only)

9

- **Installation**: `npm install rehype-react`

10

11

## Core Imports

12

13

```javascript

14

import rehypeReact from "rehype-react";

15

```

16

17

For re-exported types:

18

19

```typescript

20

import rehypeReact, { Components, Options } from "rehype-react";

21

```

22

23

## Basic Usage

24

25

```javascript

26

import { Fragment, createElement } from "react";

27

import * as prod from "react/jsx-runtime";

28

import rehypeParse from "rehype-parse";

29

import rehypeReact from "rehype-react";

30

import { unified } from "unified";

31

32

// Production JSX runtime configuration

33

const production = {

34

Fragment: prod.Fragment,

35

jsx: prod.jsx,

36

jsxs: prod.jsxs

37

};

38

39

// Transform HTML to JSX

40

const processor = unified()

41

.use(rehypeParse, { fragment: true })

42

.use(rehypeReact, production);

43

44

const html = '<h2>Hello, world!</h2><p>Welcome to my page 👀</p>';

45

const file = await processor.process(html);

46

const jsxElement = file.result; // JSX.Element ready to render

47

```

48

49

## Architecture

50

51

rehype-react operates within the unified ecosystem as a compiler plugin:

52

53

- **Unified Integration**: Registers as a compiler that transforms hast (HTML AST) to JSX.Element

54

- **JSX Runtime Abstraction**: Works with any JSX runtime (React, Preact, Solid, etc.) through configurable runtime functions

55

- **Framework Compatibility**: Handles framework-specific differences through configuration options

56

- **Type Safety**: Full TypeScript support with proper type inference and module augmentation

57

58

## Capabilities

59

60

### Main Plugin Function

61

62

Main plugin function that transforms HTML into JSX for various frameworks.

63

64

```typescript { .api }

65

/**

66

* Turn HTML into preact, react, solid, svelte, vue, etc.

67

* Registers a compiler that returns a JSX.Element where compilers typically return string.

68

* When using .stringify on unified, the result is such a JSX.Element.

69

* When using .process (or .processSync), the result is available at file.result.

70

*

71

* @param options - Configuration (required)

72

* @returns Nothing (undefined) - Plugin registers itself on the processor

73

*/

74

declare function rehypeReact(options: Options): undefined;

75

export default rehypeReact;

76

```

77

78

### Configuration Options

79

80

Complete configuration interface for the plugin.

81

82

```typescript { .api }

83

interface Options {

84

/** Fragment component from JSX runtime (required) */

85

Fragment: Fragment;

86

87

/** Dynamic JSX function (required in production mode) */

88

jsx?: Jsx;

89

90

/** Static JSX function (required in production mode) */

91

jsxs?: Jsx;

92

93

/** Development JSX function (required in development mode) */

94

jsxDEV?: JsxDev;

95

96

/** Custom component mapping (optional) */

97

components?: Partial<Components>;

98

99

/** Whether to use jsxDEV (development) or jsx/jsxs (production) */

100

development?: boolean;

101

102

/** Specify casing for attribute names */

103

elementAttributeNameCase?: 'html' | 'react';

104

105

/** Pass the hast element node to components */

106

passNode?: boolean;

107

108

/** HTML or SVG namespace context */

109

space?: 'html' | 'svg';

110

111

/** Specify casing for CSS property names in style objects */

112

stylePropertyNameCase?: 'css' | 'dom';

113

114

/** Convert obsolete align props to CSS style props */

115

tableCellAlignToStyle?: boolean;

116

}

117

```

118

119

### Component Mapping

120

121

Type definition for custom component mapping.

122

123

```typescript { .api }

124

/**

125

* Possible components to use for custom element mapping.

126

* Maps HTML element names to custom React/JSX components.

127

*/

128

type Components = {

129

[TagName in keyof JSX.IntrinsicElements]?: ComponentType<any>;

130

} & {

131

[key: string]: ComponentType<any>;

132

};

133

```

134

135

### JSX Runtime Types

136

137

Core JSX runtime function signatures and component types compatible with multiple frameworks.

138

139

```typescript { .api }

140

/** Global JSX namespace for element types - Framework agnostic */

141

declare global {

142

namespace JSX {

143

interface Element {}

144

interface IntrinsicElements {

145

[elemName: string]: any;

146

}

147

}

148

}

149

150

/**

151

* Component type definition - compatible with React, Preact, Solid, Vue

152

* @template P - Props type for the component

153

*/

154

type ComponentType<P = {}> = (props: P) => JSX.Element | null;

155

156

/**

157

* Node type for children and fragment content

158

* Used by React, Preact, and other JSX frameworks

159

*/

160

type ReactNode = JSX.Element | string | number | boolean | null | undefined | ReactNode[];

161

162

/**

163

* JSX runtime fragment component

164

* Maps to: React.Fragment, preact.Fragment, solid-js.Fragment, vue.Fragment

165

*/

166

type Fragment = ComponentType<{ children?: ReactNode }>;

167

168

/**

169

* Production JSX runtime function for dynamic content

170

* Maps to: react/jsx-runtime.jsx, preact.createElement, solid-js/jsx-runtime.jsx

171

* @param type - Element type (string for HTML elements, function for components)

172

* @param props - Element props/attributes

173

* @param key - Optional React key for list items

174

*/

175

type Jsx = (

176

type: any,

177

props: Record<string, any>,

178

key?: string | number

179

) => JSX.Element;

180

181

/**

182

* Development JSX runtime function with additional debugging info

183

* Maps to: react/jsx-dev-runtime.jsxDEV

184

* @param type - Element type (string for HTML elements, function for components)

185

* @param props - Element props/attributes

186

* @param key - Optional React key for list items

187

* @param isStaticChildren - Whether children are static (React optimization)

188

* @param source - Source location for debugging (React DevTools)

189

* @param self - Component instance (React DevTools)

190

*/

191

type JsxDev = (

192

type: any,

193

props: Record<string, any>,

194

key?: string | number,

195

isStaticChildren?: boolean,

196

source?: { fileName: string; lineNumber: number; columnNumber: number },

197

self?: any

198

) => JSX.Element;

199

```

200

201

## Framework Configuration

202

203

Different JSX frameworks require specific configuration options:

204

205

### React Configuration

206

207

```javascript

208

import { unified } from "unified";

209

import rehypeParse from "rehype-parse";

210

import rehypeReact from "rehype-react";

211

import * as prod from "react/jsx-runtime";

212

213

const reactOptions = {

214

Fragment: prod.Fragment,

215

jsx: prod.jsx,

216

jsxs: prod.jsxs,

217

elementAttributeNameCase: 'react', // Uses className instead of class

218

stylePropertyNameCase: 'dom' // Uses backgroundColor instead of background-color

219

};

220

221

// Usage with React

222

const processor = unified()

223

.use(rehypeParse, { fragment: true })

224

.use(rehypeReact, reactOptions);

225

```

226

227

### Preact Configuration

228

229

```javascript

230

import { unified } from "unified";

231

import rehypeParse from "rehype-parse";

232

import rehypeReact from "rehype-react";

233

import { Fragment, createElement } from "preact";

234

235

const preactOptions = {

236

Fragment: Fragment,

237

jsx: createElement,

238

jsxs: createElement,

239

elementAttributeNameCase: 'html', // Uses class instead of className

240

stylePropertyNameCase: 'dom'

241

};

242

243

// Usage with Preact

244

const processor = unified()

245

.use(rehypeParse, { fragment: true })

246

.use(rehypeReact, preactOptions);

247

```

248

249

### Solid Configuration

250

251

```javascript

252

import { unified } from "unified";

253

import rehypeParse from "rehype-parse";

254

import rehypeReact from "rehype-react";

255

import { Fragment } from "solid-js";

256

import { jsx } from "solid-js/jsx-runtime";

257

258

const solidOptions = {

259

Fragment: Fragment,

260

jsx: jsx,

261

jsxs: jsx,

262

elementAttributeNameCase: 'html', // Uses class

263

stylePropertyNameCase: 'css' // Uses kebab-case properties

264

};

265

266

// Usage with Solid

267

const processor = unified()

268

.use(rehypeParse, { fragment: true })

269

.use(rehypeReact, solidOptions);

270

```

271

272

### Vue Configuration

273

274

```javascript

275

import { unified } from "unified";

276

import rehypeParse from "rehype-parse";

277

import rehypeReact from "rehype-react";

278

import { Fragment } from "vue";

279

import { jsx, jsxs } from "vue/jsx-runtime";

280

281

const vueOptions = {

282

Fragment: Fragment,

283

jsx: jsx,

284

jsxs: jsxs,

285

elementAttributeNameCase: 'html',

286

stylePropertyNameCase: 'dom'

287

};

288

289

// Usage with Vue

290

const processor = unified()

291

.use(rehypeParse, { fragment: true })

292

.use(rehypeReact, vueOptions);

293

```

294

295

## Development vs Production

296

297

The plugin supports both development and production JSX transforms:

298

299

### Development Mode

300

301

```javascript

302

import * as dev from "react/jsx-dev-runtime";

303

304

const developmentOptions = {

305

Fragment: dev.Fragment,

306

jsxDEV: dev.jsxDEV,

307

development: true // Enables development mode

308

};

309

```

310

311

### Production Mode

312

313

```javascript

314

import * as prod from "react/jsx-runtime";

315

316

const productionOptions = {

317

Fragment: prod.Fragment,

318

jsx: prod.jsx,

319

jsxs: prod.jsxs,

320

development: false // Default: production mode

321

};

322

```

323

324

## Custom Component Mapping

325

326

Replace HTML elements with custom components:

327

328

```javascript

329

import { MyButton, MyLink } from "./components";

330

331

const customOptions = {

332

Fragment: prod.Fragment,

333

jsx: prod.jsx,

334

jsxs: prod.jsxs,

335

components: {

336

button: MyButton, // All <button> elements become <MyButton>

337

a: MyLink, // All <a> elements become <MyLink>

338

h1: 'h2' // All <h1> elements become <h2>

339

}

340

};

341

```

342

343

### Passing Node Information to Components

344

345

When using custom components, you can access the original hast node:

346

347

```javascript

348

const MyHeading = ({ children, node, ...props }) => {

349

// node contains the original hast element

350

console.log('Original element:', node.tagName);

351

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

352

};

353

354

const nodeOptions = {

355

Fragment: prod.Fragment,

356

jsx: prod.jsx,

357

jsxs: prod.jsxs,

358

components: {

359

h1: MyHeading

360

},

361

passNode: true // Enables node prop

362

};

363

```

364

365

## Edge Cases and Special Handling

366

367

### Whitespace Handling

368

369

The plugin preserves meaningful whitespace while processing HTML:

370

371

```javascript

372

// HTML with whitespace

373

const htmlWithWhitespace = `

374

<table>

375

<tbody>

376

<tr>

377

<th>

378

Header

379

</th>

380

<td>

381

Data

382

</td>

383

</tr>

384

</tbody>

385

</table>

386

`;

387

388

// Whitespace is preserved in the JSX output

389

const result = await processor.process(htmlWithWhitespace);

390

```

391

392

### Table Cell Alignment

393

394

By default, obsolete `align` attributes on table cells are converted to CSS styles:

395

396

```javascript

397

// HTML: <th align="right">Header</th>

398

// Becomes: <th style={{textAlign: 'right'}}>Header</th>

399

400

// To disable this behavior:

401

const options = {

402

Fragment: prod.Fragment,

403

jsx: prod.jsx,

404

jsxs: prod.jsxs,

405

tableCellAlignToStyle: false // Keep align attribute as-is

406

};

407

```

408

409

### Doctype Handling

410

411

DOCTYPE declarations are automatically filtered out during transformation as they are not valid JSX:

412

413

```javascript

414

// HTML with doctype

415

const htmlWithDoctype = '<!DOCTYPE html><h1>Hello</h1>';

416

417

// Only the h1 element is transformed; doctype is ignored

418

const result = await processor.process(htmlWithDoctype);

419

// Result: <h1>Hello</h1>

420

```

421

422

## Error Handling

423

424

The plugin may throw errors in these cases:

425

426

- **Missing Runtime**: If required JSX runtime functions (`Fragment`, `jsx`, `jsxs`, or `jsxDEV`) are not provided

427

- **Invalid Configuration**: If `development: true` but `jsxDEV` is not provided, or vice versa

428

- **Transformation Errors**: If the underlying `hast-util-to-jsx-runtime` encounters invalid HTML structures

429

430

## Security Considerations

431

432

⚠️ **XSS Warning**: Using rehype-react with untrusted HTML can expose applications to cross-site scripting attacks. Always sanitize HTML before transformation:

433

434

```javascript

435

import rehypeSanitize from "rehype-sanitize";

436

437

const safeProcessor = unified()

438

.use(rehypeParse, { fragment: true })

439

.use(rehypeSanitize) // Sanitize before transformation

440

.use(rehypeReact, options);

441

```

442

443

## Module Declaration Extensions

444

445

The plugin extends unified's TypeScript definitions:

446

447

```typescript { .api }

448

declare module 'unified' {

449

interface CompileResultMap {

450

/** JSX Element result type for rehype-react */

451

JsxElement: JSX.Element;

452

}

453

}

454

```

455

456

This enables proper TypeScript inference when using the plugin with unified processors.