--- url: /guide/introduction.md --- You are viewing documentation for the upcoming [**v5**](https://github.com/kitajs/html/tree/next) release. For the current stable version, see the [v4 readme on npm](https://www.npmjs.com/package/@kitajs/html).# What is Kita Html Kita Html is a JSX runtime where every element evaluates to a string. Where React's `
` produces a virtual DOM node that must be reconciled and serialized, Kita Html's `
` returns `'
'` directly. There is no intermediate representation, no diffing step, and no serialization pass. The JSX you write compiles to function calls that concatenate strings. This architecture makes Kita Html significantly faster than virtual DOM-based renderers for any scenario where the output is an HTML string: server-side rendering, static site generation, email templates, HTMX applications, or any HTTP handler that sends HTML over the wire. [Go to getting started](/guide/getting-started.md) ## Performance through simplicity A virtual DOM renderer performs three operations per render cycle: it constructs an object tree, diffs it against the previous tree, and serializes the result to a string. Kita Html skips all three. The TypeScript compiler rewrites JSX expressions into `jsx()` and `jsxs()` function calls at build time. At runtime, those functions concatenate attribute strings and child strings into a single result. The output is the final HTML with no post-processing. ```tsx twoslash kita import { jsx as __jsx } from '@kitajs/html/jsx-runtime' const username: string = 'Username' export let html: JSX.Element // ---cut--- // What you write html = (

{username}

) // What TypeScript compiles to html = __jsx('div', { class: 'card', children: __jsx('h1', { safe: true, children: username }) }) // Click on the <> icon in the top right to see the compiled output ``` This directness is why Kita Html benchmarks 7-40x faster than React's `renderToString` across real-world component trees. The runtime has zero dependencies beyond TypeScript itself. [Read more about how JSX becomes HTML](/guide/how-jsx-becomes-html.md) ## XSS protection Because `JSX.Element` is a `string`, the runtime cannot distinguish between HTML produced by a component and raw user input injected as a child. Children are not escaped by default. This is a deliberate trade-off for performance and composability, and it is fully addressed by three layers of protection that work together to make accidental XSS practically impossible. The `safe` attribute escapes children at render time. Adding it to any native element causes the runtime to pass all children through HTML entity escaping before concatenation. ```tsx twoslash kita // @noErrors let userInput = `` as const // ---cut--- const html =
{userInput}
// ^? ``` A TypeScript language service plugin analyzes every JSX expression in your editor and flags any child whose type could carry unescaped HTML. The same analysis runs as a CLI tool [`xss-scan`](/guide/xss/scanner-cli.md) in CI/CD pipelines, failing the build on any finding. Between the editor diagnostics and the CI gate, unsafe expressions are caught before they reach production. **The only way to ship XSS-vulnerable code is to explicitly suppress the warnings.** [Read more about the XSS protection system](/guide/xss/safe-attribute.md) ## Async components and Suspense Kita Html supports async components natively. Any function component that returns a `Promise` is valid JSX. When an async child appears anywhere in the tree, the entire parent chain becomes a `Promise` through automatic propagation. ```tsx twoslash kita const db = { async getUser(id: string) { return { name: 'Arthur' } } } // ---cut--- async function UserCard({ id }: { id: string }) { const user = await db.getUser(id) return
{user.name}
} // The result is a Promise because UserCard is async, // Type still is JSX.Element so it can be used in JSX const html = ``` For streaming scenarios, the Suspense component renders a fallback immediately and replaces it with the resolved content as each async subtree completes. This uses HTTP chunked transfer encoding to stream updates to the client without waiting for the entire page to resolve. A small inline script handles the client-side DOM replacement. ```tsx twoslash kita=stream import { Suspense, renderToStream } from '@kitajs/html/suspense' async function UserCard({ id }: { id: string }) { return
Async Component
} // ---cut--- const stream = renderToStream((rid) => ( Loading...
}> )) // Pipe the stream to your HTTP response or use one of our integrations. ``` Each Suspense boundary operates independently, so fast components appear instantly while slow ones show their fallback. The `rid` parameter ties each Suspense instance to a specific request for safe concurrent rendering. - [Read more about Suspense streaming](/guide/async/async-components.md) ## Packages As of now, Kita Html is composed of two main packages: - `@kitajs/html` is the core runtime that compiles JSX to strings and provides Suspense streaming. - `@kitajs/ts-html-plugin` is the TypeScript plugin and CLI scanner for XSS detection. Official [framework integrations](/integrations/overview.md) are available for Fastify, Elysia, and others. The core runtime works with any framework that accepts strings. - [Read more about the packages and integrations](/integrations/overview.md) --- url: /guide/getting-started.md --- You are viewing documentation for the upcoming [**v5**](https://github.com/kitajs/html/tree/next) release. For the current stable version, see the [v4 readme on npm](https://www.npmjs.com/package/@kitajs/html).# Getting Started Install `@kitajs/html` and `@kitajs/ts-html-plugin` together. The first is the JSX runtime; the second provides editor diagnostics and the `xss-scan` CLI for catching XSS at compile time. ```sh [npm] npm i @kitajs/html@next @kitajs/ts-html-plugin@next ``` ```sh [yarn] yarn add @kitajs/html@next @kitajs/ts-html-plugin@next ``` ```sh [pnpm] pnpm add @kitajs/html@next @kitajs/ts-html-plugin@next ``` ```sh [bun] bun add @kitajs/html@next @kitajs/ts-html-plugin@next ``` ## TypeScript configuration Add the following to your `tsconfig.json`. The `jsx` and `jsxImportSource` fields tell TypeScript to compile JSX using the Kita Html runtime. The `plugins` entry activates the XSS detection plugin in your editor. ```json title="tsconfig.json" { "compilerOptions": { "jsx": "react-jsx", "jsxImportSource": "@kitajs/html", "plugins": [{ "name": "@kitajs/ts-html-plugin" }] } } ``` If your editor uses a globally installed TypeScript version instead of the project's local copy, the plugin will not load. In VS Code, configure the workspace to use the local TypeScript: ```json title=".vscode/settings.json" { "typescript.tsdk": "node_modules/typescript/lib", "typescript.enablePromptUseWorkspaceTsdk": true } ``` ## XSS scanner Add `xss-scan` to your test script so it runs in CI alongside your tests. The CLI performs the same XSS analysis as the editor plugin, but against your entire codebase. ```json title="package.json" { "scripts": { "test": "xss-scan && vitest" } } ``` ## Verification Write the following in a `.tsx` file: ```tsx twoslash // @errors: 88601 console.log(
{String.name}
) ``` Your editor should show an XSS error on `String.name`, because its type is `string` and it is not escaped. If you see the error, the plugin is working. Run `xss-scan` from the terminal to confirm the CLI catches the same issue. If no error appears, verify that your editor is using the workspace TypeScript version and that the `plugins` array is present in the `tsconfig.json` that covers the file. --- url: /guide/how-jsx-becomes-html.md --- You are viewing documentation for the upcoming [**v5**](https://github.com/kitajs/html/tree/next) release. For the current stable version, see the [v4 readme on npm](https://www.npmjs.com/package/@kitajs/html).# How JSX Becomes HTML The transformation from JSX to an HTML string happens in two stages: a compile-time rewrite by TypeScript and a runtime evaluation by the Kita Html functions. ## Compile time When `tsconfig.json` specifies `jsx: "react-jsx"` and `jsxImportSource: "@kitajs/html"`, TypeScript rewrites every JSX expression into a function call. Elements with a single child call `jsx()`. Elements with multiple children call `jsxs()`. Attributes and children are passed as a single props object. ```tsx title="Source TSX" twoslash kita const html = (
    {[1, 2].map((i) => (
  1. {i}
  2. ))}
) ``` TypeScript compiles this to: ```tsx title="Compiled output" twoslash kita // @showEmit const html = (
    {[1, 2].map((i) => (
  1. {i}
  2. ))}
) ``` The JSX syntax is fully removed at compile time. The runtime never parses JSX. ## Runtime The `jsx()` and `jsxs()` functions receive the tag name and the props object. They perform three operations in sequence: serialize attributes into an HTML attribute string, serialize children into a content string, and concatenate the opening tag, content, and closing tag. If any child is a `Promise`, the concatenation returns a `Promise` instead of a `string`. This propagation is automatic: a single async component anywhere in the tree makes every ancestor async up to the root. Void elements like `
`, ``, and `` skip the closing tag entirely. The runtime checks the tag name against a list ordered by frequency so the most common void elements resolve in a single comparison. Attributes are always escaped. The `class` attribute accepts arrays for conditional composition. The `style` attribute accepts both strings and objects, with automatic camelCase-to-kebab-case conversion for object keys. Boolean attributes like `disabled` render as valueless attributes when `true` and are omitted when `false`. --- url: /guide/ai-support.md --- You are viewing documentation for the upcoming [**v5**](https://github.com/kitajs/html/tree/next) release. For the current stable version, see the [v4 readme on npm](https://www.npmjs.com/package/@kitajs/html).# AI Support Kita Html exposes multiple AI-friendly entry points so coding agents can understand the runtime without falling back to React assumptions. Use the installable skill when you want behavior guidance inside an agent, then use the published docs formats to provide focused or broad reference material. ## Agent skill The `kita-html` skill is designed for coding agents that support installable skills. It teaches the core runtime model, XSS rules, framework adapters, async components, and Suspense streaming so the agent stops treating every `.tsx` file as React. Install it with: ```sh [npx] npx skills add kitajs/html --skill kita-html ``` ```sh [yarn] yarn dlx skills add kitajs/html --skill kita-html ``` ```sh [pnpm] pnpm dlx skills add kitajs/html --skill kita-html ``` ```sh [bunx] bunx skills add kitajs/html --skill kita-html ``` ```sh [deno] deno run -A npm:skills add kitajs/html --skill kita-html ``` After installation, prompt the agent normally. Useful examples: ```text Build this Fastify page with Kita Html and stream async sections. ``` ```text Fix this Kita TSX so user bios render safely and xss-scan passes. ``` ```text Convert this React-style server component into Kita Html. ``` ## Documentation formats Kita Html publishes the docs in three useful formats. - [`llms.txt`](https://html.kitajs.org/llms.txt) is the lightweight index. Use it when AI should pick the right page first. - [`llms-full.txt`](https://html.kitajs.org/llms-full.txt) is the full concatenated documentation dump. Use it when AI needs broad Kita Html context in a single fetch. - Every page also has a raw Markdown version, such as [Getting Started.md](https://html.kitajs.org/guide/getting-started.md) or [Safe Attribute.md](https://html.kitajs.org/guide/xss/safe-attribute.md). Choose the smallest format that matches the task. `llms.txt` is usually best for discovery. Raw Markdown is usually best for one topic. `llms-full.txt` is best when the agent needs a full view of the framework. ## Project instructions If your editor or coding agent supports project instruction files, point it at Kita Html before it writes JSX. ```markdown title="AGENTS.md" # AGENTS.md This project uses Kita Html, not React. ## Docs - Kita Html index: https://html.kitajs.org/llms.txt - Kita Html full docs: https://html.kitajs.org/llms-full.txt - Getting started: https://html.kitajs.org/guide/getting-started.md - Safe attribute: https://html.kitajs.org/guide/xss/safe-attribute.md ## Rules - `JSX.Element` is `string | Promise`. - Children are not escaped by default. - Use `safe` on native elements that render untrusted text. - Run `xss-scan` during validation. ``` If your tool also supports a file like `CLAUDE.md`, reference the same instructions there. The important part is that the agent sees Kita-specific rules before it starts generating TSX. ## What To Share With AI Share the narrowest document that answers the task. - For setup issues, share [Getting Started.md](https://html.kitajs.org/guide/getting-started.md). - For escaping questions, share [Safe Attribute.md](https://html.kitajs.org/guide/xss/safe-attribute.md) or [Safety Rules.md](https://html.kitajs.org/guide/xss/safety-rules.md). - For streaming and async behavior, share [Using Suspense.md](https://html.kitajs.org/guide/async/using-suspense.md). - For framework integration, share the matching Fastify, Express, or Elysia guide. - For broader assistance, start with [`llms.txt`](https://html.kitajs.org/llms.txt) and move to [`llms-full.txt`](https://html.kitajs.org/llms-full.txt) only when the task needs wider context. --- url: /guide/xss/safe-attribute.md --- You are viewing documentation for the upcoming [**v5**](https://github.com/kitajs/html/tree/next) release. For the current stable version, see the [v4 readme on npm](https://www.npmjs.com/package/@kitajs/html).# Using the Safe Attribute Every child expression in Kita Html renders without escaping by default. To escape user input, apply the `safe` attribute to the nearest native element wrapping the expression. ## Native elements Add `safe` to the element that directly contains the dynamic content. The runtime passes all children through HTML entity escaping before concatenation. ```tsx twoslash kita // @noErrors let userInput = `` as const // ---cut--- const html =
{userInput}
// ^? ``` Without `safe`, malicious input executes. Consider a user profile where the description field contains `
`. Rendering this without escaping closes the container early, injects a script tag, and runs arbitrary code. The `safe` attribute converts the angle brackets to `<` and `>`, rendering the payload as harmless text. Place `safe` on the innermost element that holds the untrusted value. Do not add it to a parent wrapper, as that would escape the HTML of child components too. ```tsx twoslash kita function UserCard({ name, bio }: { name: string; bio: string }) { return (

{name}

{bio}

) } // ---cut-after--- const html = ``` ## Component children The `safe` attribute only applies to native elements. If you pass an unsafe value as a child to a component, you must either escape it manually or wrap it in a Fragment with the `safe` attribute to tell the plugin it's already escaped. This prevents components from accidentally rendering unescaped HTML when they receive dynamic content as children. ```tsx twoslash kita let userInput: string = 'User input!' import { Fragment, Children, escapeHtml } from '@kitajs/html' function MyComponent({ children }: { children: Children }) { return
{children}
} let html: JSX.Element // ---cut--- html = ( {userInput} ) // Or escape explicitly when the component doesn't support safe html = {escapeHtml(userInput)} ``` ## Template literal helper The `e` tagged template is an alias to `escapeHtml()` that you can use as interpolated content in template literals. It provides a convenient way to escape dynamic values outside of JSX. ```tsx twoslash kita const userName = '' as const // ---cut--- import { e } from '@kitajs/html' const html = e`Hello, ${userName}!` ``` ## Suppression conventions When the XSS detection plugin flags a value that you know is safe, you can suppress the warning without adding `safe` to the element, which would escape all children and potentially break components. ::: danger Suppressing warnings is dangerous because it allows unescaped HTML to slip through. Only use these techniques when you have a guarantee of safety. ::: Prefix the variable name with `safe`. The plugin treats any identifier starting with `safe` as pre-escaped. ```tsx twoslash kita const rawInput = "" as const function sanitizeElsewhere(raw: string): string { // Some external library or custom logic that guarantees safety return raw.replace(//g, '>') } // ---cut--- const safeContent = sanitizeElsewhere(rawInput) // ^? const html =
{safeContent}
// ^? ``` Following the same logic, prefixing a variable with `unsafe` explicitly marks it as unescaped and triggers a warning if used in JSX. ```tsx twoslash kita // @errors: 88601 const unsafeContent = 'My safe string' as const const html =
{unsafeContent}
``` ::: warning Manual casts and naming conventions are not enforced by the compiler. They rely on developer discipline and code reviews to ensure safety. Use them judiciously and document the rationale for any exceptions. ::: Cast the expression to `'safe'` inline. This tells the plugin to skip the check for that specific usage and not warn about possible XSS vulnerabilities. ```tsx twoslash kita const content: string = '' // ---cut--- const html =
{content as 'safe'}
``` Call `Html.escapeHtml()` directly. The plugin recognizes the return value as escaped. ```tsx twoslash kita const content: string = '' // ---cut--- import { Html } from '@kitajs/html' const html =
{Html.escapeHtml(content)}
``` --- url: /guide/xss/scanner-cli.md --- You are viewing documentation for the upcoming [**v5**](https://github.com/kitajs/html/tree/next) release. For the current stable version, see the [v4 readme on npm](https://www.npmjs.com/package/@kitajs/html).# Running the XSS Scanner The `xss-scan` CLI ships with `@kitajs/ts-html-plugin` and performs project-wide XSS analysis from the command line. ## Usage ```bash xss-scan [options] [files...] ``` The command can also be invoked as `ts-html-plugin`, which is an alias for the same CLI. When called without file arguments, it scans all files included by the project's `tsconfig.json`. When file paths are provided, only those files are analyzed. ```bash # Scan entire project xss-scan # Scan specific files xss-scan src/pages/login.tsx src/pages/profile.tsx ``` ## Options `--cwd ` sets the working directory. Defaults to the current directory. `-p, --project ` specifies the path to `tsconfig.json`. Defaults to `tsconfig.json` in the working directory. `-s, --simplified` outputs diagnostics in a compact single-line format, useful for machine parsing. ## Exit codes The scanner exits with code 0 when no issues are found, 1 when errors are present, and 2 when only warnings exist. This makes it suitable for CI gates where you want to fail on errors but optionally allow warnings. ## Integration Add the scanner to your test script so it runs before or alongside your test suite. ```json { "scripts": { "test": "xss-scan && vitest" } } ``` In a GitHub Actions workflow: ```yaml - name: XSS scan run: npx xss-scan ``` The scanner uses the same TypeScript program and analysis engine as the editor plugin, so findings are identical between the two. --- url: /guide/xss/safety-rules.md --- You are viewing documentation for the upcoming [**v5**](https://github.com/kitajs/html/tree/next) release. For the current stable version, see the [v4 readme on npm](https://www.npmjs.com/package/@kitajs/html).# Safety Rules The XSS detection engine classifies every JSX child expression as safe or unsafe based on its TypeScript type. This page lists the rules the engine follows. ## Safe types Expressions with these types render without escaping and produce no diagnostic: - `number`, `boolean`, `bigint`, `null`, `undefined` - String literals (e.g. `'hello'` rather than `string`) - `JSX.Element` (the output of another component, already rendered) - `Html.Children` (the typed children alias) - Return values of `Html.escapeHtml()`, `Html.escape()`, or `e` template literals - Variables whose name starts with `safe` (e.g. `safeContent`, `safeHtml`) ## Unsafe types Expressions with these types trigger a diagnostic unless wrapped with `safe` or escaped manually: - `string` (a dynamic string that could contain HTML) - `any` (the engine cannot verify safety without a concrete type) - Objects relying on `toString()` for rendering ## Composite types Union types are safe only if every member of the union is safe. `string | number` is unsafe because `string` is unsafe. `number | boolean` is safe because both members are safe. Both branches of ternary and binary expressions are checked independently. Even if one branch is unreachable at runtime, the engine still analyzes its type. ```tsx twoslash // @errors: 88601 const condition = true const safeValue = 42 const unsafeString = 'user input' ;
{condition ? safeValue : unsafeString}
``` ## Exceptions Content inside ` ``` The `