JSX renderer
kubb/jsx is Kubb's JSX-based renderer, an alternative to building files with the ast.factory node builders from kubb/kit. It provides a JSX runtime and a set of built-in components so a generator can emit files and markdown through JSX.
Setup
Point your tsconfig.json at the kubb/jsx runtime so JSX syntax compiles against its components instead of React's:
{
"compilerOptions": {
"jsx": "react-jsx",
"jsxImportSource": "kubb/jsx"
}
}With that in place, .tsx files in the plugin resolve jsx-runtime and jsx-dev-runtime from kubb/jsx automatically.
jsxRenderer()
jsxRenderer creates a renderer instance with two members, render and files. Call render with a JSX element, then read the generated files back off files.
import { jsxRenderer } from 'kubb/jsx'
import { File, Function, Type } from 'kubb/jsx'
const renderer = jsxRenderer()
await renderer.render(
<File baseName="petStore.ts" path="src/gen/petStore.ts">
<File.Source>
<Type name="Pet">{'{ id: number; name: string }'}</Type>
<Function name="getPet" async>
{"return fetch('/pets')"}
</Function>
</File.Source>
</File>,
)
const files = renderer.filesBuilt-in components
kubb/jsx groups its built-in components into four sets:
- Core components (
File,File.Source,File.Import,File.Export) declare an output file and the imports, exports, and source blocks that make it up. - JavaScript components (
Const,Function,Function.Arrow,Type) emit TypeScript declarations. - Markdown components (
Callout,Frontmatter,Heading,List,Paragraph) emit markdown. Jsxembeds a raw JSX string in the generated output.
| Component | Category | Emits |
|---|---|---|
File | Core | File entry |
File.Source | Core | Source block |
File.Import | Core | Import statement |
File.Export | Core | Export statement |
Const | JavaScript | TypeScript |
Function | JavaScript | TypeScript |
Function.Arrow | JavaScript | TypeScript |
Type | JavaScript | TypeScript |
Callout | Markdown | Markdown |
Frontmatter | Markdown | Markdown |
Heading | Markdown | Markdown |
List | Markdown | Markdown |
Paragraph | Markdown | Markdown |
Jsx | JSX | Raw JSX |
Core
File is the container. Its members File.Source, File.Import, and File.Export attach source blocks, imports, and exports to it.
File
Declares a generated output file. Pass both baseName and path to register a file entry. Omit both to render the children inline without creating a file.
| Prop | Type | Description |
|---|---|---|
baseName | `${string}.${string}` | File name with extension, such as petStore.ts. |
path | string | Fully qualified path to the generated file. |
meta? | object | null | Metadata attached to the file node for plugins to read. |
banner? | string | null | Text prepended before the source blocks. |
footer? | string | null | Text appended after the source blocks. |
copy? | string | null | Absolute path to copy verbatim into the output, bypassing the parser. |
children? | KubbReactNode | Source blocks, imports, and exports that make up the file. |
<File baseName="petStore.ts" path="src/models/petStore.ts">
<File.Source name="Pet" isExportable isIndexable>
{`export type Pet = { id: number; name: string }`}
</File.Source>
</File>File.Source
Marks a block of source text that belongs to the enclosing File. The children are the source string.
| Prop | Type | Description |
|---|---|---|
name? | string | null | Identifies the source for deduplication and barrel generation. |
isExportable? | boolean | null | Prepend the export keyword. |
isIndexable? | boolean | null | Include the source in barrel and index generation. |
isTypeOnly? | boolean | null | Mark the source as a type-only export. |
children? | KubbReactNode | Source text of the block. |
<File.Source name="PetId" isTypeOnly isExportable>
{`export type PetId = string`}
</File.Source>File.Import
Declares an import for the enclosing File. The renderer emits it at the top of the generated file.
| Prop | Type | Description |
|---|---|---|
name | string | Array<string | { propertyName: string; name?: string }> | Binding to import. A string for a default or namespace import, an array for named imports. |
path | string | Module specifier to import from. |
root? | string | null | Root used to resolve the import path relative to the file. |
isTypeOnly? | boolean | null | Emit import type. |
isNameSpace? | boolean | null | Emit import * as name. |
<File.Import name={['useState']} path="react" />
// import { useState } from 'react'
<File.Import name="z" path="zod" isNameSpace />
// import * as z from 'zod'File.Export
Declares an export for the enclosing File. The renderer emits it at the top of the generated file.
| Prop | Type | Description |
|---|---|---|
name? | string | Array<string> | null | Binding to export. Omit for a wildcard export. |
path | string | Module specifier to export from. |
isTypeOnly? | boolean | null | Emit export type. |
asAlias? | boolean | null | Emit export * as name. |
<File.Export name={['Pet']} path="./models/petStore" />
// export { Pet } from './models/petStore'
<File.Export path="./models/petStore" isTypeOnly />
// export type * from './models/petStore'JavaScript
The JavaScript components emit TypeScript declarations. Nest them inside a File.Source so the renderer writes them into a .ts file.
Const
Generates a TypeScript constant declaration. The children are the initializer expression.
| Prop | Type | Description |
|---|---|---|
name | string | Identifier of the constant. |
export? | boolean | null | Prepend the export keyword. |
type? | string | null | Type annotation written after const name:. |
asConst? | boolean | null | Append as const after the initializer. |
JSDoc? | JSDoc | null | JSDoc block prepended to the declaration. |
children? | KubbReactNode | Initializer expression. |
<Const export name="petSchema" type="z.ZodType<Pet>">
{`z.object({ id: z.number() })`}
</Const>
// export const petSchema: z.ZodType<Pet> = z.object({ id: z.number() })Function
Generates a TypeScript function declaration. The children are the function body.
| Prop | Type | Description |
|---|---|---|
name | string | Identifier of the function. |
export? | boolean | null | Prepend the export keyword. |
default? | boolean | null | Emit default after export to make this the default export. |
async? | boolean | null | Emit async. Wraps returnType in Promise<…>. |
params? | string | null | Parameter list written between the parentheses. |
generics? | string | Array<string> | null | Generic type parameters. An array joins with commas. |
returnType? | string | null | Return type annotation written after :. |
JSDoc? | JSDoc | null | JSDoc block prepended to the declaration. |
children? | KubbReactNode | Function body. |
<Function export async name="getPet" generics={['TData = Pet']} params="petId: string" returnType="TData">
{'return client.get("/pets/" + petId)'}
</Function>
// export async function getPet<TData = Pet>(petId: string): Promise<TData> { … }Function.Arrow
Generates an arrow function assigned to a const. Takes every Function prop plus singleLine.
| Prop | Type | Description |
|---|---|---|
singleLine? | boolean | null | Render a braceless expression body instead of a block. |
<Function.Arrow export name="double" params="n: number" returnType="number" singleLine>
{`n * 2`}
</Function.Arrow>
// export const double = (n: number): number => n * 2Type
Generates a TypeScript type alias. The children are the type expression. name must start with an uppercase letter or the component throws.
| Prop | Type | Description |
|---|---|---|
name | string | Identifier of the type alias, starting with an uppercase letter. |
export? | boolean | null | Prepend the export keyword. |
JSDoc? | JSDoc | null | JSDoc block prepended to the declaration. |
children? | KubbReactNode | Type expression on the right-hand side. |
<Type export name="PetId">
{`string | number`}
</Type>
// export type PetId = string | numberMarkdown
The markdown components each emit their own source block, so they go directly inside a File rather than a File.Source. Render the file with parserMd so it is written as markdown.
import { jsxRenderer } from 'kubb/jsx'
import { File, Frontmatter, Heading, Paragraph, List, Callout } from 'kubb/jsx'
const renderer = jsxRenderer()
await renderer.render(
<File baseName="pets.md" path="src/docs/pets.md">
<Frontmatter data={{ title: 'Pets', layout: 'doc' }} />
<Heading level={2}>Pets</Heading>
<Paragraph>{'A pet object with an id and a name.'}</Paragraph>
<List items={['id: number', 'name: string']} />
<Callout type="tip">Keep the generator hot with kubb start --watch.</Callout>
</File>,
)Callout
Renders a GitHub-style alert using the > [!TYPE] blockquote syntax.
| Prop | Type | Description |
|---|---|---|
type | 'tip' | 'note' | 'important' | 'warning' | 'caution' | Callout kind, mapped to the uppercase label. |
title? | string | null | Title rendered on the marker line. |
children | string | Body text. Each line is quoted with > . |
<Callout type="warning" title="Heads up">Breaking change in v6.</Callout>
// > [!WARNING] Heads up
// > Breaking change in v6.Frontmatter
Emits a YAML frontmatter envelope at the top of a markdown file. Place it as the first child of the File.
| Prop | Type | Description |
|---|---|---|
data | Record<string, unknown> | Object serialized to YAML between --- fences. |
<Frontmatter data={{ title: 'Pets', layout: 'doc' }} />
// ---
// title: Pets
// layout: doc
// ---Heading
Renders an ATX-style markdown heading.
| Prop | Type | Description |
|---|---|---|
level | 1 | 2 | 3 | 4 | 5 | 6 | Heading depth, matching the number of # characters. |
children | string | Heading text. |
<Heading level={2}>Installation</Heading>
// ## InstallationList
Renders a markdown list, one entry per line.
| Prop | Type | Description |
|---|---|---|
items | ReadonlyArray<string> | List entries, one per line. |
ordered? | boolean | null | Emit a numbered list. Defaults to a bullet list. |
<List ordered items={['First', 'Second']} />
// 1. First
// 2. SecondParagraph
Renders a markdown paragraph. Inline markdown passes through verbatim.
| Prop | Type | Description |
|---|---|---|
children | string | Paragraph text. |
<Paragraph>{'A pet object with `id` and `name` fields.'}</Paragraph>JSX
Jsx
Embeds a raw JSX string in the generated source, including fragments. Use it inside a Function to emit a component body. The children must be a plain string.
| Prop | Type | Description |
|---|---|---|
children? | string | Raw JSX string embedded verbatim. |
<Function name="MyComponent" export>
<Jsx>{'return (\n <>\n <div>Hello</div>\n </>\n)'}</Jsx>
</Function>See also
- Kit API for
defineGenerator'srendererfield and theast.factoryalternative to JSX - Creating plugins for how a generator wires a renderer into its output
- Kit API: rendering for how
jsxRenderersits next tocreateRenderer