$ rezi

Using JSX

Rezi provides a JSX runtime (@rezi-ui/jsx) that lets you write widget trees using JSX syntax instead of the ui.* function API.

Rezi provides a JSX runtime (@rezi-ui/jsx) that lets you write widget trees using JSX syntax instead of the ui.* function API.

Setup

  1. Install the JSX package:

    npm install @rezi-ui/jsx
  2. Configure TypeScript (tsconfig.json):

    {
      "compilerOptions": {
        "jsx": "react-jsx",
        "jsxImportSource": "@rezi-ui/jsx"
      }
    }
  3. Use .tsx file extensions.

Example

import { rgb } from "@rezi-ui/core";
import { createNodeApp } from "@rezi-ui/node";
import { Button, Column, Divider, Row, Text } from "@rezi-ui/jsx";

type State = { count: number };

const app = createNodeApp<State>({
  initialState: { count: 0 },
});

app.view((state) => (
  <Column p={1} gap={1}>
    <Text style={{ fg: rgb(120, 200, 255), bold: true }}>Counter</Text>
    <Row gap={2}>
      <Text>Count: {state.count}</Text>
      <Button id="inc" label="+1" />
    </Row>
    <Divider />
    <Text style={{ dim: true }}>Press q to quit</Text>
  </Column>
));

app.keys({
  q: () => app.stop(),
});

await app.start();

Available JSX elements

@rezi-ui/jsx exports components for all core widgets. Props match the corresponding ui.* function.

ui.* APIJSX component
ui.text(...)<Text>
ui.box(...)<Box>
ui.row(...)<Row>
ui.column(...)<Column>
ui.grid(...)<Grid>
ui.hstack(...)<HStack>
ui.vstack(...)<VStack>
ui.button(...)<Button>
ui.input(...)<Input>
ui.slider(...)<Slider>
ui.tabs(...)<Tabs>
ui.accordion(...)<Accordion>
ui.breadcrumb(...)<Breadcrumb>
ui.pagination(...)<Pagination>
ui.table(...)<Table>
ui.modal(...)<Modal>
...(all core widgets through <ToastContainer>)

Lowercase intrinsic elements are also supported (for example <column>, <grid>, <hstack>, and <tabs>). These map directly to the JSX runtime factories and do not require importing components.

<HStack>/<VStack> (and <hstack>/<vstack>) follow ui.hstack/ui.vstack behavior: they emit row/column VNodes with a default gap of 1 when no gap is provided.

JSX vs ui.* API

Both APIs produce the same VNode trees. Choose based on preference:

// JSX style
<Column p={1}>
  <Text style={{ bold: true }}>Hello</Text>
  <Row gap={2}>
    <Button id="ok" label="OK" />
    <Button id="cancel" label="Cancel" />
  </Row>
</Column>

// ui.* style
ui.column({ p: 1 }, [
  ui.text("Hello", { style: { bold: true } }),
  ui.row({ gap: 2 }, [
    ui.button({ id: "ok", label: "OK" }),
    ui.button({ id: "cancel", label: "Cancel" }),
  ]),
])

The ui.* API has zero runtime overhead — it's direct function calls. The JSX runtime adds a thin createElement layer. Both are extremely fast.

Fragments

Use fragments to group elements without a container:

<>
  <Text>Line 1</Text>
  <Text>Line 2</Text>
</>

Note: JSX vs ui.*

@rezi-ui/jsx is the native Rezi JSX runtime. It creates Rezi VNodes directly and does not use React.

If you prefer explicit function calls, use ui.*. If you prefer JSX syntax, use @rezi-ui/jsx.

On this page