---
title: TypeScript setup
---

# TypeScript setup

Vincle uses the standard JSX transform. Configure it once, in `tsconfig.json`
or your build tool: `.tsx` files then need no import.

## tsconfig.json

```json title="tsconfig.json"
{
  "compilerOptions": {
    "jsx": "react-jsx",
    "jsxImportSource": "@vincle/core"
  }
}
```

## Deno

Deno's built-in JSX transform works as is. Set the import source in `deno.json`:

```json title="deno.json"
{
  "compilerOptions": {
    "jsx": "react-jsx",
    "jsxImportSource": "npm:@vincle/core"
  },
  "imports": {
    "@vincle/core": "npm:@vincle/core"
  }
}
```

Deno's `jsx: "precompile"` mode works too: Vincle exports the three helpers
it needs (`jsxTemplate`, `jsxAttr`, `jsxEscape`). `dangerouslySetInnerHTML` still renders there;
prefer `{raw(html)}` as a child.

## Vite / esbuild

Set the import source in your build config instead of `tsconfig.json`:

```ts
// vite.config.ts
export default defineConfig({
  esbuild: { jsx: "automatic", jsxImportSource: "@vincle/core" },
});
```

Either one works: Vite reads both.

### Precompile plugin (recommended for production)

The precompile plugin rewrites JSX into template literals: fewer allocations,
faster rendering, smaller bundles.

```ts
import precompile from "@vincle/precompile/vite";

export default defineConfig({
  esbuild: { jsx: "automatic", jsxImportSource: "@vincle/core" },
  plugins: [precompile()],
});
```

Static attributes get the runtime's checks at build time, by default: a
literal `href="javascript:…"` never reaches the bundle. See
[Build-time sanitization](/integration/precompile#build-time-sanitization).

## Attribute types

Every HTML and SVG element is typed per element (`src` on `<img>`, `colSpan` on
`<td>`), inside `@vincle/core`: `<div clas="card">` is a compile error.

## Where to next

- [First render](/guide/getting-started/first-render): your first component
- [Elements & attributes](/guide/jsx/elements-attributes): `class`, `style`, booleans
