# Agents

> Install the NatUI Agent Skill and connect coding agents to current machine-readable documentation.

Canonical: https://natui.dev/docs/agents

NatUI provides an installable Agent Skill and a complete Markdown view of this
documentation. Use the skill for reusable implementation guidance, then use
`llms.txt` to find the current pages for the task. They complement each other:
the skill teaches the workflow, while the documentation supplies the current
API and platform details. The skill follows the
[Agent Skills specification](https://agentskills.io/specification). The
repository's `/skills` directory is a distribution catalog, so install the
skill into the client that will use it.

## Install the NatUI skill [#install-the-natui-skill]

Install the skill from GitHub with the
[open `skills` CLI](https://github.com/vercel-labs/skills):

```bash
npx skills add https://github.com/floklein/natui --skill natui
```

The interactive flow detects compatible agents and lets you choose project or
global scope. Review the
[skill source](https://github.com/floklein/natui/tree/main/skills/natui)
before installing it. The NatUI skill contains instructions and references,
with no executable scripts.

## Give agents current documentation [#give-agents-current-documentation]

| Resource                                            | Use                                                                                                        |
| --------------------------------------------------- | ---------------------------------------------------------------------------------------------------------- |
| [`https://natui.dev/llms.txt`](/llms.txt)           | Start here. It is the compact index of documentation pages and descriptions.                               |
| [`https://natui.dev/llms-full.txt`](/llms-full.txt) | Load the complete documentation corpus when a task genuinely spans most of NatUI.                          |
| `https://natui.dev/docs/<page>.md`                  | Fetch one clean Markdown page, such as [`components/inputs`](https://natui.dev/docs/components/inputs.md). |
| `Accept: text/markdown`                             | Request Markdown from the normal documentation URL when the client supports content negotiation.           |

Resolve relative links from `llms.txt` against `https://natui.dev`. Prefer the
compact index plus a few targeted pages over loading the full corpus into every
task. The compact index follows the
[`llms.txt` proposal](https://llmstxt.org/). `llms-full.txt` is a convenient
complete export, not a required part of that proposal.

```bash
curl -H "Accept: text/markdown" \
  https://natui.dev/docs/guides/controlled-state
```

Every documentation page also exposes **Copy Markdown** and **View Markdown**
actions for interactive use.

## Agent workflow [#agent-workflow]

1. Install or invoke the `natui` skill.
2. Read [`llms.txt`](/llms.txt) and select only the relevant setup, component,
   guide, and status pages.
3. Inspect the current checkout before editing. NatUI is in alpha and is not a
   published registry package.
4. Implement with React state and NatUI components. Do not introduce DOM
   elements, CSS, or browser event APIs.
5. Build the matching native host and validate on the target platform.
6. Use a real native window before claiming visible or interactive behavior.

Use this bootstrap prompt after installation:

```text
Use the installed NatUI skill to implement this task. Begin with
https://natui.dev/llms.txt, fetch only the relevant Markdown pages, inspect the
current checkout because NatUI is in alpha, and verify the result on the
requested native platform.
```

## High-value entry points [#high-value-entry-points]

* [Source setup](/docs/start/source-setup)
* [First app](/docs/start/first-app)
* [Component catalog](/docs/components)
* [Controlled state](/docs/guides/controlled-state)
* [Testing and debugging](/docs/guides/testing-and-debugging)
* [Platform support](/docs/status/platform-support)
* [Verification status](/docs/status/verification)

---

# NatUI documentation

> Build real SwiftUI and WinUI 3 desktop interfaces with React and TypeScript.

Canonical: https://natui.dev/docs

NatUI is an alpha React 19 renderer for real native desktop controls. Your TypeScript and React state stay in JavaScript while SwiftUI on macOS or WinUI 3 on Windows owns layout, theming, focus, and accessibility.

There is no webview, Electron runtime, or browser layout engine.

```tsx typecheck
import { useState } from 'react';
import { Button, HStack, Text, VStack, run } from 'natui';

function App() {
  const [count, setCount] = useState(0);

  return (
    <VStack spacing={12} padding={20} alignment="leading">
      <Text font="largeTitle" weight="bold">Hello, native</Text>
      <HStack spacing={8}>
        <Button onPress={() => setCount((value) => value - 1)}>-</Button>
        <Text font="title2" monospaced>{String(count)}</Text>
        <Button onPress={() => setCount((value) => value + 1)}>+</Button>
      </HStack>
    </VStack>
  );
}

await run(<App />, { title: 'my app', width: 480, height: 320 });
```

## Explore the documentation [#explore-the-documentation]

* [Set up an AI agent](/docs/agents) with the NatUI skill and machine-readable documentation.
* [Get started](/docs/start) from a source checkout.
* Browse all [37 components](/docs/components).
* Learn how [controlled state](/docs/guides/controlled-state) stays responsive across the native bridge.
* Choose between [Node and embedded runtime modes](/docs/guides/runtime-modes).
* Package an embedded entry as a [native application](/docs/guides/application-bundles).
* Review the current [platform support](/docs/status/platform-support) before depending on a feature.

## Current status [#current-status]

NatUI is still in Alpha and is not a published registry package. Both hosts
have real-window verification for the base demo, kitchen-sink app-shell
workflow, and their embedded JavaScript runtimes. The repository-local
packager emits a macOS `.app` or one self-contained Windows EXE.

---

# Bridge API

> Reference the lower-level bridge that batches commits and dispatches native events.

Canonical: https://natui.dev/docs/api/bridge

`Bridge` connects a renderer to a `Transport`. It owns the operation buffer, live event targets, startup handshake, sequence acknowledgements, and debug request waiters.

### BridgeOptions


| Property | Type | Required | Description |
| --- | --- | --- | --- |
| `requestTimeoutMs` | `number \| undefined` | No | Dump/screenshot reply timeout override (mainly for tests). |

### ReadyInfo


| Property | Type | Required | Description |
| --- | --- | --- | --- |
| `platform` | `string` | Yes |  |
| `protocol` | `number` | Yes |  |
| `hostApi` | `number` | Yes |  |

```ts
const bridge = new Bridge(transport, {
  requestTimeoutMs: 10_000,
});
```

Important methods include:

| Method                    | Purpose                                          |
| ------------------------- | ------------------------------------------------ |
| `waitForReady(timeoutMs)` | Await the buffered or future host handshake      |
| `push(op)`                | Buffer one protocol operation                    |
| `flush()`                 | Send one atomic commit                           |
| `sendWindow(props)`       | Configure the native window                      |
| `requestDump()`           | Request the native tree                          |
| `requestScreenshot(path)` | Request a host-rendered PNG                      |
| `emitDebugEvent(...)`     | Synthesize a host event                          |
| `editDebugValue(...)`     | Perform an optimistic host edit                  |
| `quit()`                  | Send the quit message                            |
| `dispose(reason)`         | Reject pending requests and mark the bridge dead |

The reconciler also uses target registration, `latestSeqFor`, and `setPriorityRunner` to dispatch handlers and enforce controlled values.

This is an advanced API. Most applications should use `run`.

---

# natui/components

> Reference the Node-free component entrypoint and its shared TypeScript types.

Canonical: https://natui.dev/docs/api/components

This entrypoint exports all 37 host components and their prop types without importing the Node process runtime.

```tsx
import { Button, Text, VStack } from 'natui/components';
```

Use it for embedded bundles and anywhere that should remain free of Node built-ins. Use the primary `natui` entrypoint for a normal Node-driven application.

## Shared types [#shared-types]

### CommonProps


| Property | Type | Required | Description |
| --- | --- | --- | --- |
| `padding` | `number \| EdgeInsets \| undefined` | No |  |
| `background` | `string \| undefined` | No |  |
| `cornerRadius` | `number \| undefined` | No |  |
| `frame` | `Frame \| undefined` | No |  |
| `opacity` | `number \| undefined` | No |  |
| `disabled` | `boolean \| undefined` | No |  |
| `hidden` | `boolean \| undefined` | No |  |
| `color` | `string \| undefined` | No | Foreground color. |
| `help` | `string \| undefined` | No | Tooltip. |
| `tag` | `string \| undefined` | No | Stable row identity for selectable containers (List/Table selection). A selectable List reports and receives selection as its rows' tags. |
| `badge` | `string \| number \| undefined` | No | Badge shown on Tab items and List rows (counts, short strings). |
| `accessibilityLabel` | `string \| undefined` | No | Assistive-tech label (VoiceOver / Narrator). |
| `accessibilityHint` | `string \| undefined` | No | Assistive-tech hint describing the result of activating the element. |
| `accessibilityIdentifier` | `string \| undefined` | No | Stable identifier for UI automation (AX identifier / AutomationId). |
| `key` | `string \| number \| undefined` | No |  |

* `Color`
* `EdgeInsets`
* `Frame`
* `CommonProps`
* `ContainerProps`
* `FontStyle`
* `PickerOption`
* `MenuItemRole`
* `MenuActionSpec`
* `MenuDividerSpec`
* `MenuItemSpec`
* `MenuSpec`
* `ToolbarItemSpec`
* `AlertButtonSpec`
* `TableColumnSpec`
* `TableRowSpec`
* `SortDescriptor`

See the [component catalog](/docs/components) for grouped usage and platform behavior.

---

# API reference

> Reference the public NatUI package entrypoints and lower-level renderer interfaces.

Canonical: https://natui.dev/docs/api

NatUI exposes three package entrypoints:

* [`natui`](/docs/api/natui) for components, the Node runtime, protocol types, and lower-level building blocks
* [`natui/components`](/docs/api/components) for the component API without Node runtime imports
* [`natui/inproc`](/docs/api/inproc) for an embedding host

Advanced exports are public for tests and custom transport experiments:

* [`Bridge`](/docs/api/bridge)
* [`createNatuiRenderer`](/docs/api/renderer)
* [`Transport`](/docs/api/transport)
* [Protocol types and constants](/docs/api/protocol)

These APIs describe the current alpha release and may change before a stable release.

---

# natui/inproc

> Reference the in-process runtime for a native host that embeds JavaScript.

Canonical: https://natui.dev/docs/api/inproc

## runEmbedded [#runembedded]

### RunEmbeddedOptions


| Property | Type | Required | Description |
| --- | --- | --- | --- |
| `onClose` | `(() => void) \| undefined` | No | Called once when the native window asks the application to close. |
| `readyTimeoutMs` | `number \| undefined` | No | Startup handshake timeout override (mainly for tests). |
| `title` | `string \| undefined` | No |  |
| `width` | `number \| undefined` | No |  |
| `height` | `number \| undefined` | No |  |
| `minWidth` | `number \| undefined` | No |  |
| `minHeight` | `number \| undefined` | No |  |

```ts
function runEmbedded(
  element: ReactNode,
  options?: RunEmbeddedOptions,
): Promise<EmbeddedApp>
```

Mounts a React element inside an embedding native host and resolves after the
first React commit. `RunEmbeddedOptions` includes the window property shape
used by the protocol, plus `onClose` and a startup timeout override.

The host must provide:

* `globalThis.__natui_send(json)` for JavaScript-to-host messages
* A ready handshake with compatible protocol and host API levels after evaluating the bundle

The module installs `globalThis.__natui_recv(json)` for host-to-JavaScript messages.
One embedded application may be active in a JavaScript runtime at a time. A
second `runEmbedded` call rejects instead of replacing the active receive hook.

```tsx
import { Text } from 'natui/components';
import { runEmbedded } from 'natui/inproc';

const app = await runEmbedded(<Text>Hello</Text>, {
  title: 'embedded NatUI',
  width: 400,
  height: 240,
  onClose() {
    console.log('Window close requested');
  },
});

app.update(<Text>Hello again</Text>);
app.quit();
```

## EmbeddedApp [#embeddedapp]

### EmbeddedApp


| Property | Type | Required | Description |
| --- | --- | --- | --- |
| `platform` | `EmbeddedPlatform` | Yes |  |
| `state` | `EmbeddedAppState` | Yes |  |
| `update` | `(element: ReactNode) => void` | Yes | Re-render with a new element. Throws after shutdown begins. |
| `quit` | `() => void` | Yes | Synchronously unmount React, flush effect cleanup, ask the host to quit, and detach the in-process receive hook. Safe to call more than once. |

| Member            | Purpose                                                      |
| ----------------- | ------------------------------------------------------------ |
| `platform`        | Ready-handshake platform, `macos` or `windows`               |
| `state`           | Current lifecycle state: `running`, `stopping`, or `stopped` |
| `update(element)` | Re-render while the application is running                   |
| `quit()`          | Unmount and stop the embedded application                    |

`quit()` is synchronous and idempotent. Its first call unmounts React, runs
effect cleanup, sends one host quit message, rejects pending bridge work, and
removes `globalThis.__natui_recv`. Calls after shutdown begins do nothing.
`update()` throws after shutdown begins.

A native window close invokes `onClose` once and then uses the same shutdown
path. A startup compatibility failure also requests host shutdown and detaches
the receive hook.

The entrypoint contains no Node built-ins and is intended for browser-platform
bundling. The repository implements this embedding contract with JavaScriptCore
on macOS and V8 on Windows. Packaged applications use this same API. See
[application bundles](/docs/guides/application-bundles).

---

# natui entrypoint

> Reference run, RunOptions, NatuiApp, components, protocol types, and advanced exports.

Canonical: https://natui.dev/docs/api/natui

The primary entrypoint exports every component plus the Node-driven runtime.

## run [#run]

```ts
function run(
  element: ReactNode,
  options?: RunOptions,
): Promise<NatuiApp>
```

Starts the host, validates its platform, protocol, and host API handshake,
sends window properties, and mounts the React element.

## RunOptions [#runoptions]

`RunOptions` includes optional `title`, `width`, `height`, `minWidth`, and `minHeight`, plus:

### RunOptions


| Property | Type | Required | Description |
| --- | --- | --- | --- |
| `host` | `string \| HostCommand \| undefined` | No | Host binary override; defaults to NATUI_HOST env or the in-repo build. |
| `onClose` | `(() => void) \| undefined` | No | Called when the user closes the window. Default: unmount and exit. |
| `readyTimeoutMs` | `number \| undefined` | No | Startup handshake timeout override (mainly for tests). |
| `title` | `string \| undefined` | No |  |
| `width` | `number \| undefined` | No |  |
| `height` | `number \| undefined` | No |  |
| `minWidth` | `number \| undefined` | No |  |
| `minHeight` | `number \| undefined` | No |  |

| Property         | Purpose                                             |
| ---------------- | --------------------------------------------------- |
| `host`           | Host executable string or `{ cmd, args? }` override |
| `onClose`        | Callback for native window close                    |
| `readyTimeoutMs` | Startup handshake timeout override                  |

Without `onClose`, closing the native window unmounts React, sends `quit`, and exits the Node process.

## NatuiApp [#natuiapp]

### NatuiApp


| Property | Type | Required | Description |
| --- | --- | --- | --- |
| `dump` | `() => Promise<TreeNode>` | Yes | Debug: ask the host for its current native tree. |
| `screenshot` | `(path: string) => Promise<string>` | Yes | Debug: host renders its window content to a PNG at `path`. |
| `emit` | `(id: number, name: string, payload?: Record<string, unknown>) => void` | Yes | Debug: make the host synthesize a user event on node `id`. |
| `edit` | `(id: number, value: unknown) => void` | Yes | Debug: make the host perform a real optimistic user edit on node `id` (same code path as typing/dragging: local write, seq, change event). |
| `update` | `(element: ReactNode) => void` | Yes | Re-render with a new element (e.g. for external hot reload). |
| `quit` | `() => void` | Yes | Unmount, quit the host, close the transport. |

| Method                     | Result                                                |
| -------------------------- | ----------------------------------------------------- |
| `dump()`                   | Resolves to the current native `TreeNode`             |
| `screenshot(path)`         | Resolves to the written PNG path                      |
| `emit(id, name, payload?)` | Synthesizes a debug event                             |
| `edit(id, value)`          | Performs an optimistic debug edit                     |
| `update(element)`          | Renders a new React element                           |
| `quit()`                   | Unmounts, asks the host to quit, and closes transport |

## Other exports [#other-exports]

The entrypoint re-exports all components, protocol types,
`PROTOCOL_VERSION`, `HOST_API_VERSION`, `ROOT_ID`, `Bridge`,
`createNatuiRenderer`, `spawnStdioTransport`, `Transport`, `HostCommand`, and
`defaultHostCommand`.

---

# Protocol API

> Reference NatUI protocol constants, messages, operations, and tree types.

Canonical: https://natui.dev/docs/api/protocol

## Constants [#constants]

```ts
const PROTOCOL_VERSION = 1;
const HOST_API_VERSION = 1;
const ROOT_ID = 0;
```

`PROTOCOL_VERSION` gates wire-format compatibility. `HOST_API_VERSION` is an
additive native capability level for components and host behavior that retain
the same wire format. A renderer accepts an equal or newer host API, but not
an older one.

## Value types [#value-types]

`PropValue` is JSON-compatible data: strings, numbers, booleans, null, arrays, and plain objects. `SerializedProps` maps property names to those values.

```ts
type PropValue =
  | string
  | number
  | boolean
  | null
  | PropValue[]
  | { [key: string]: PropValue };

type SerializedProps = Record<string, PropValue>;
```

## WindowProps [#windowprops]

### WindowProps


| Property | Type | Required | Description |
| --- | --- | --- | --- |
| `title` | `string \| undefined` | No |  |
| `width` | `number \| undefined` | No |  |
| `height` | `number \| undefined` | No |  |
| `minWidth` | `number \| undefined` | No |  |
| `minHeight` | `number \| undefined` | No |  |

```ts
interface WindowProps {
  title?: string;
  width?: number;
  height?: number;
  minWidth?: number;
  minHeight?: number;
}
```

## Operations [#operations]

The `Op` union includes `create`, `createText`, `append`, `insert`, `remove`, `update`, `text`, and `clear`. An update may include `ack` for controlled-value echo suppression.

```ts
type Op =
  | { op: 'create'; id: number; kind: string; props: SerializedProps }
  | { op: 'createText'; id: number; text: string }
  | { op: 'append'; parent: number; child: number }
  | { op: 'insert'; parent: number; child: number; before: number }
  | { op: 'remove'; parent: number; child: number }
  | { op: 'update'; id: number; props: SerializedProps; ack?: number }
  | { op: 'text'; id: number; text: string }
  | { op: 'clear' };
```

## Messages [#messages]

`OutboundMessage` includes:

* `window`
* `commit`
* `dump`
* `screenshot`
* `emit`
* `edit`
* `quit`

`InboundMessage` includes:

* `ready`
* `event`
* `window` close
* `tree`
* `shot`

## TreeNode [#treenode]

A debug tree node contains an `id`, `kind`, optional serialized `props`, optional raw `text`, and optional child nodes.

### TreeNode


| Property | Type | Required | Description |
| --- | --- | --- | --- |
| `id` | `number` | Yes |  |
| `kind` | `string` | Yes |  |
| `props` | `SerializedProps \| undefined` | No |  |
| `text` | `string \| undefined` | No |  |
| `children` | `TreeNode[] \| undefined` | No |  |

See the [wire protocol](/docs/internals/protocol) for ordering, lifecycle, event, selection, and sequence-acknowledgement semantics.

---

# Renderer API

> Reference createNatuiRenderer and the custom React renderer interface.

Canonical: https://natui.dev/docs/api/renderer

### NatuiRenderer


| Property | Type | Required | Description |
| --- | --- | --- | --- |
| `render` | `(element: ReactNode, onCommitted?: () => void) => void` | Yes |  |
| `unmount` | `() => void` | Yes |  |
| `container` | `RootContainer` | Yes |  |

```ts
function createNatuiRenderer(bridge: Bridge): NatuiRenderer
```

Creates a React 19 concurrent root backed by a NatUI bridge.

`NatuiRenderer` provides:

| Member                          | Purpose                                                   |
| ------------------------------- | --------------------------------------------------------- |
| `render(element, onCommitted?)` | Update the React root                                     |
| `unmount()`                     | Synchronously unmount and flush native removal operations |
| `container`                     | Internal root container and node-id allocator             |

Native events run at React's discrete event priority and synchronously flush work. That allows the bridge to determine immediately whether React adopted a controlled value.

Most applications should use `run`, which creates and coordinates the renderer, bridge, transport, handshake, window, and shutdown behavior.

---

# Transport API

> Reference the NatUI transport contract and standard-stream host implementation.

Canonical: https://natui.dev/docs/api/transport

## Transport [#transport]

### Transport

A bidirectional NDJSON channel to a native host process, over the host's
stdin/stdout (we spawn the host and pipe both ends). This is the only
supported transport; see docs/protocol.md.

| Property | Type | Required | Description |
| --- | --- | --- | --- |
| `send` | `(msg: OutboundMessage) => void` | Yes |  |
| `onMessage` | `(cb: (msg: InboundMessage) => void) => void` | Yes |  |
| `onExit` | `(cb: (code: number \| null) => void) => void` | Yes |  |
| `close` | `() => void` | Yes |  |

```ts
interface Transport {
  send(msg: OutboundMessage): void;
  onMessage(cb: (msg: InboundMessage) => void): void;
  onExit(cb: (code: number | null) => void): void;
  close(): void;
}
```

A transport delivers typed protocol messages in both directions and reports host exit.

## HostCommand [#hostcommand]

### HostCommand


| Property | Type | Required | Description |
| --- | --- | --- | --- |
| `cmd` | `string` | Yes |  |
| `args` | `string[] \| undefined` | No |  |

```ts
interface HostCommand {
  cmd: string;
  args?: string[];
}
```

## spawnStdioTransport [#spawnstdiotransport]

```ts
function spawnStdioTransport(host: HostCommand): Transport
```

Spawns a host process and exchanges newline-delimited JSON over its standard input and output. Host standard error is inherited for diagnostics.

## defaultHostCommand [#defaulthostcommand]

Checks `NATUI_HOST` first, then searches upward from the current directory for known macOS or Windows build outputs.

The shipped host process protocol uses standard streams. `natui/inproc` provides a separate internal transport for an embedding host.

---

# App shell and data

> Coordinate native window chrome, navigation, selection, and sorting from React state.

Canonical: https://natui.dev/docs/guides/app-shell-and-data

## Root-attached chrome [#root-attached-chrome]

Place `MenuBar` and `Toolbar` directly under the React root. Hosts hoist them into native window chrome instead of inserting them in normal layout.

```tsx
function App() {
  return (
    <>
      <MenuBar menus={menus} onSelect={handleMenu} />
      <Toolbar items={toolbarItems} onAction={handleToolbar} />
      <SplitView>{content}</SplitView>
    </>
  );
}
```

macOS accepts the first root-level menu bar and toolbar. Windows hoists chrome components wherever they are created, but relying on that difference makes the tree non-portable.

## Stable selection identity [#stable-selection-identity]

Use `tag` for list rows and `id` for table rows:

```tsx
<List value={projectId} onChange={(value) => setProjectId(value as string | null)}>
  {projects.map((project) => (
    <Label key={project.id} tag={project.id} systemImage="folder">
      {project.name}
    </Label>
  ))}
</List>
```

Selection can be a string, a string array, or null. Providing the `value` prop, even with null, enables selection.

## Sort in the application [#sort-in-the-application]

The native table emits a requested `SortDescriptor`. Keep data operations in JavaScript:

```tsx
const visibleRows = useMemo(
  () => sortRows(rows, sort),
  [rows, sort],
);

<Table
  columns={columns}
  rows={visibleRows}
  sort={sort}
  onSortChange={setSort}
/>
```

Filtering follows the same model. The host receives final row data and does not own a separate sorted or filtered copy.

## Use serializable specs [#use-serializable-specs]

Menu, toolbar, alert, and table structures are data props rather than React child trees. Keep them JSON-compatible and update the data when checkmarks, toggle states, disabled states, or rows change.

---

# Application bundles

> Package a NatUI entry as a native macOS app or a portable Windows executable.

Canonical: https://natui.dev/docs/guides/application-bundles

NatUI includes a repository-local reference packager for turning an embedded
React entry into a native application artifact. The packaged application runs
React inside JavaScriptCore on macOS or V8 on Windows. It does not start Node
at application runtime.

## Package the demo [#package-the-demo]

From the repository root:

```bash
pnpm package:demo
```

The command builds `packages/natui`, reads
`examples/demo/natui.app.json`, bundles the configured entry with esbuild, and
builds the native host for the current operating system and architecture.

Output goes to `examples/demo/dist/package`:

* Windows x64:
  `NatUIDemo-0.1.0-windows-x64.exe`
* Windows ARM64:
  `NatUIDemo-0.1.0-windows-arm64.exe`
* macOS:
  `NatUIDemo.app`

Packaging is platform-specific. Build each macOS architecture on that
architecture. Windows packaging supports x64 and ARM64 targets.

## Application configuration [#application-configuration]

The demo configuration is:

```json
{
  "$schema": "../../schemas/natui-app.schema.json",
  "schemaVersion": 1,
  "id": "dev.natui.demo",
  "name": "NatUI Demo",
  "version": "0.1.0",
  "buildNumber": "1",
  "entry": "src/main-embedded.tsx",
  "executable": "NatUIDemo",
  "output": "dist/package"
}
```

| Field           | Purpose                                                 |
| --------------- | ------------------------------------------------------- |
| `schemaVersion` | Application configuration schema, currently `1`         |
| `id`            | Lowercase reverse-DNS application identifier            |
| `name`          | Native display name, up to 80 characters                |
| `version`       | Three-part application version such as `1.2.3`          |
| `buildNumber`   | Positive integer string used by native version metadata |
| `entry`         | Browser-compatible embedded React entry                 |
| `executable`    | Native executable name without spaces                   |
| `output`        | Output directory relative to `natui.app.json`           |
| `icons.macos`   | Optional `.icns` path                                   |
| `icons.windows` | Optional `.ico` path                                    |

Entry, output, and icon paths must stay inside the application directory.
Unknown configuration fields fail packaging instead of being ignored.

The configured entry must call `runEmbedded` from `natui/inproc`. Imports from
`natui/components` remain free of Node built-ins and can be included in the
browser-targeted application bundle.

## Platform artifacts [#platform-artifacts]

### Windows [#windows]

Windows packaging produces one portable, architecture-specific, self-contained
EXE. The file contains the minified application JavaScript, generated
manifest, WinUI host, .NET runtime, Windows App SDK runtime, and V8
dependencies.

The .NET single-file host extracts its runtime dependencies into a cache under
the current user's temporary directory at launch. This extraction is managed
by the runtime and does not install machine-wide dependencies. Copy the one
EXE to ship the application.

### macOS [#macos]

macOS packaging produces a standard `.app` directory. Its executable is under
`Contents/MacOS`, while `main.js` and `manifest.json` are under
`Contents/Resources/NatUI`. Copy the complete `.app` directory when moving the
application.

The generated `Info.plist` carries the configured application identifier,
display name, version, build number, minimum macOS version, and optional icon.

## Generated manifest and compatibility [#generated-manifest-and-compatibility]

Each artifact contains a generated manifest shaped like:

```json
{
  "schemaVersion": 1,
  "id": "dev.natui.demo",
  "name": "NatUI Demo",
  "version": "0.1.0",
  "buildNumber": "1",
  "entry": "main.js",
  "entrySha256": "<64 lowercase hexadecimal characters>",
  "protocolVersion": 1,
  "minHostApi": 1,
  "platform": "windows",
  "architecture": "x64"
}
```

Before evaluating JavaScript, the native loader validates:

* Bundle schema version
* Exact wire protocol version
* Minimum host API level
* Target platform and architecture
* SHA-256 digest of `main.js`

The protocol version covers message compatibility. The host API level covers
additive native components and host behavior that use the same wire format.
A newer host API can run a bundle that requires an older level. An older host
cannot run a bundle that requires newer capabilities.

## Embedded application lifecycle [#embedded-application-lifecycle]

`runEmbedded` resolves to an `EmbeddedApp` after the first React commit:

```tsx
const app = await runEmbedded(<App />, {
  title: 'My app',
  onClose() {
    console.log('The native window requested close');
  },
});

app.update(<App />);
app.quit();
```

`quit()` is idempotent. The first call synchronously unmounts React, runs
effect cleanup, sends one native quit request, disposes pending bridge work,
and detaches `globalThis.__natui_recv`. Later calls do nothing. A native window
close invokes `onClose` once and follows the same shutdown path.

Startup protocol or host API incompatibility also asks the native host to quit
and removes the receive hook, so a broken packaged application does not remain
alive without a usable React tree.

## Verify the packaged lifecycle [#verify-the-packaged-lifecycle]

Run:

```bash
pnpm verify:package
```

This command rebuilds the demo package for the current platform, launches the
artifact from an unrelated working directory, validates the ready handshake,
waits for the demo tree, requests a native close, and requires a clean exit.
It needs a normal desktop window session.

## Current boundaries [#current-boundaries]

The reference packager does not currently provide:

* Code signing
* macOS notarization
* Installer generation
* Automatic updates
* Single-instance orchestration
* Multi-window application APIs

Packaging creates runnable artifacts. Release distribution still requires the
platform-specific signing, notarization, installer, and update work appropriate
for the application.

---

# Common props

> Apply shared layout, appearance, identity, and accessibility props to NatUI components.

Canonical: https://natui.dev/docs/guides/common-props

Most host components accept these optional properties:

| Prop                      | Type                   | Purpose                                 |
| ------------------------- | ---------------------- | --------------------------------------- |
| `padding`                 | `number \| EdgeInsets` | Uniform or per-edge inset               |
| `background`              | `Color`                | Background color                        |
| `cornerRadius`            | `number`               | Rounded background corners              |
| `frame`                   | `Frame`                | Fixed and minimum or maximum dimensions |
| `opacity`                 | `number`               | Visual opacity                          |
| `disabled`                | `boolean`              | Disables interaction                    |
| `hidden`                  | `boolean`              | Hides the native view                   |
| `color`                   | `Color`                | Foreground color                        |
| `help`                    | `string`               | Native tooltip                          |
| `tag`                     | `string`               | Stable row identity for selection       |
| `badge`                   | `string \| number`     | Short badge on supported rows or tabs   |
| `accessibilityLabel`      | `string`               | Assistive-technology label              |
| `accessibilityHint`       | `string`               | Result or purpose of activation         |
| `accessibilityIdentifier` | `string`               | Stable UI automation identifier         |

Colors are `#RRGGBB` or `#RRGGBBAA` strings.

```tsx
<Text
  padding={{ top: 8, bottom: 8, leading: 12, trailing: 12 }}
  background="#E94F37"
  color="#FFFFFF"
  cornerRadius={8}
  frame={{ minWidth: 120, maxWidth: 'infinity' }}
  accessibilityLabel="Build status"
>
  Ready
</Text>
```

## Frames [#frames]

`Frame` accepts `width`, `height`, `minWidth`, `maxWidth`, `minHeight`, and `maxHeight`. A maximum can be a number or `"infinity"`.

All dimensions use logical points. A frame participates in native layout and is not a CSS box.

## JSON boundary [#json-boundary]

Props that cross to the host must contain strings, finite numbers, booleans, null, arrays, or plain objects made from those values. Event-handler functions stay in JavaScript and are never serialized.

Invalid values such as `BigInt`, circular objects, class instances, nested functions, or non-finite numbers are reported with their component kind and prop path, then omitted.

## Platform details [#platform-details]

* Container foreground color cascades to descendants until a child supplies
  its own `color`.
* Rounded panel backgrounds clip their children to `cornerRadius`.
* `Image` paints padding, background, and corner radius around its native
  symbol on both hosts.
* Accessibility identifiers map to AX identifiers on macOS and Automation IDs on Windows.

---

# Controlled state

> Keep native inputs responsive and authoritative with React state and sequence acknowledgements.

Canonical: https://natui.dev/docs/guides/controlled-state

NatUI inputs are React-controlled even though interaction begins in another process. The host applies an optimistic local value immediately, then reports the edit to JavaScript.

```tsx
const [query, setQuery] = useState('');

<SearchField value={query} onChange={setQuery} />
```

## Sequence acknowledgements [#sequence-acknowledgements]

Each controlled native edit increments a monotonic sequence number for that node:

1. The host applies the user's edit locally.
2. It emits a `change` event carrying `seq`.
3. React runs the handler at discrete priority and commits the new props.
4. The bridge adds the highest processed sequence as `ack` to the update.
5. The host accepts the value when the acknowledgement catches up.

If another native edit occurs first, an older acknowledgement cannot overwrite the newer local value. Other props in that update still apply.

## React remains authoritative [#react-remains-authoritative]

If a handler rejects or transforms an edit, NatUI sends a corrective update after the synchronous event flush:

```tsx
const [code, setCode] = useState('');

<TextField
  value={code}
  onChange={(next) => setCode(next.toUpperCase().slice(0, 8))}
/>
```

This behavior also covers controls with no handler. A native edit is visible optimistically, then settles back to the current React value.

## Controlled and request semantics [#controlled-and-request-semantics]

Input `change` events carry sequence numbers. Request events, such as `Table` sorting, do not. A sort request asks the application to reorder rows and provide a new descriptor; it is not a host-owned value edit.

The sequence protocol applies where a host performs an optimistic native
change: text fields, search fields, toggles, sliders, pickers, date pickers,
steppers, text editors, list and table selection, tab selection, disclosure
state, presentation dismissal, and split visibility.

---

# Guides

> Learn the state, layout, runtime, and verification patterns behind NatUI applications.

Canonical: https://natui.dev/docs/guides

* [Common props](/docs/guides/common-props) covers layout, appearance, identity, and accessibility.
* [Controlled state](/docs/guides/controlled-state) explains optimistic native input and sequence acknowledgements.
* [App shell and data](/docs/guides/app-shell-and-data) connects menus, navigation, lists, tables, and application state.
* [Overlays](/docs/guides/overlays) covers sheets, alerts, popovers, and dismissal.
* [Runtime modes](/docs/guides/runtime-modes) compares the Node sidecar and embedded JavaScript paths.
* [Application bundles](/docs/guides/application-bundles) packages embedded JavaScript as a native `.app` or self-contained EXE.
* [Testing and debugging](/docs/guides/testing-and-debugging) documents contract tests and native debug messages.

NatUI uses the platform layout engine. Design for native semantics and equivalent capability instead of assuming pixel-identical output.

---

# Overlays

> Coordinate controlled sheet, alert, and popover presentation.

Canonical: https://natui.dev/docs/guides/overlays

Sheet, alert, and popover visibility belongs to React state:

```tsx
const [open, setOpen] = useState(false);

<>
  <Button onPress={() => setOpen(true)}>Open</Button>
  <Sheet value={open} onChange={setOpen}>
    <Editor onDone={() => setOpen(false)} />
  </Sheet>
</>
```

Native dismissal emits `change(false)`. If React retains `true`, the normal controlled-value correction restores the presented state.

## Avoid unnecessary mounted work [#avoid-unnecessary-mounted-work]

Sheet children are part of the native tree even while not presented. Gate expensive content when it does not need to retain local state:

```tsx
<Sheet value={open} onChange={setOpen}>
  {open ? <ExpensiveEditor /> : null}
</Sheet>
```

## Alert event order [#alert-event-order]

When an alert button is pressed, `onSelect(buttonId)` runs before `onChange(false)`. Handle the chosen action in `onSelect`, then let `onChange` update presentation state.

## Popover structure [#popover-structure]

A `Popover` has two roles among its children:

* Ordinary children render as the anchor.
* One `PopoverContent` child provides the presented body.

## Screenshot limitations [#screenshot-limitations]

macOS and Windows host screenshots capture their own native window content.
Popup layers such as sheets, alerts, popovers, and open menus can be outside
that rendered surface.

Use tree dumps and event assertions for popup behavior instead of treating screenshots as complete proof.

---

# Runtime modes

> Choose between the Node development process and an embedded JavaScript runtime.

Canonical: https://natui.dev/docs/guides/runtime-modes

## Node process [#node-process]

The current development path runs React in Node. `run` locates and spawns the native host, then exchanges newline-delimited JSON over standard input and output.

```tsx
import { run } from 'natui';

await run(<App />, { title: 'NatUI app' });
```

This mode provides the simplest development loop and works with the macOS and Windows hosts.

## Embedded JavaScript [#embedded-javascript]

Both hosts can evaluate a browser-targeted bundle in-process. macOS uses
system JavaScriptCore and Windows uses V8. `runEmbedded` resolves to a
controller after the first React commit:

```tsx
import { VStack, Text } from 'natui/components';
import { runEmbedded } from 'natui/inproc';

const app = await runEmbedded(
  <VStack padding={20}>
    <Text>Hello from embedded JavaScript</Text>
  </VStack>,
  { title: 'embedded app' },
);

app.update(
  <VStack padding={20}>
    <Text>Updated in place</Text>
  </VStack>,
);
```

Build and run the included embedded demo:

```bash
pnpm build:host:macos
pnpm build
pnpm --filter natui-demo build:embedded
hosts/macos/.build/release/natui-host --bundle examples/demo/dist/embedded.js
```

On Windows, build the WinUI host and launch the same bundle:

```powershell
dotnet build hosts/windows/NatuiHost -c Release -p:Platform=x64
pnpm build
pnpm --filter natui-demo build:embedded
hosts\windows\NatuiHost\bin\x64\Release\net8.0-windows10.0.19041.0\win-x64\NatuiHost.exe --bundle examples\demo\dist\embedded.js
```

Component imports come from `natui/components` so the bundle does not include Node built-ins. `natui/inproc` exchanges the same protocol messages through host-injected functions rather than standard streams.

Embedded mode is implemented and locally verified on both platforms through
the same lifecycle and bridge contract. `app.quit()` synchronously unmounts
React, runs effect cleanup, sends one quit request, and detaches the receive
hook. Repeated calls are safe.

## Native application packaging [#native-application-packaging]

The repository also packages the embedded demo as a native application:

```bash
pnpm package:demo
pnpm verify:package
```

The configuration lives at `examples/demo/natui.app.json`. macOS produces
`examples/demo/dist/package/NatUIDemo.app`. Windows produces one portable,
architecture-specific, self-contained EXE in the same output directory. The
Windows EXE extracts its runtime dependencies to a per-user temporary cache
when it launches.

Both artifacts contain a generated manifest and SHA-256 digest for the
JavaScript entry. The loader checks bundle schema, protocol, minimum host API,
platform, architecture, and entry integrity before evaluation.

See [application bundles](/docs/guides/application-bundles) for the
configuration, artifact layout, lifecycle, verification, and current release
boundaries.

---

# Testing and debugging

> Validate renderer contracts and inspect the real native tree with NatUI debug messages.

Canonical: https://natui.dev/docs/guides/testing-and-debugging

## Contract and unit tests [#contract-and-unit-tests]

```bash
pnpm test
pnpm build
pnpm typecheck
```

The JavaScript test suite covers reconciler mutation semantics, prop validation, bridge startup and failure behavior, sequence acknowledgements, menu and presentation data, and selection behavior.

## Real-window suites [#real-window-suites]

```bash
pnpm verify
pnpm verify:kitchen
pnpm verify:embedded
pnpm verify:package
```

These commands require a desktop window session and target the host for the
current operating system. The embedded suite proves JavaScriptCore on macOS
and V8 on Windows. The package suite first runs `pnpm package:demo`, launches
the resulting native artifact from an unrelated working directory, validates
its ready handshake and tree, then requests a normal close and requires a
clean exit.

The base Node-mode and embedded suites have passed locally against a real
Windows WinUI 3 window. The Windows CI job compiles the host, builds the
portable EXE, and inspects its single-file contents without running a GUI.

The package configuration and generated manifest also have platform-neutral
unit coverage through `pnpm test`. Those tests validate path containment,
identity fields, stable manifest content, compatibility gates, SHA-256 shape,
and macOS native metadata.

## Debug messages [#debug-messages]

`NatuiApp` exposes four debug helpers:

```tsx
const app = await run(<App />);

const tree = await app.dump();
await app.screenshot('/absolute/path/result.png');
app.emit(nodeId, 'press');
app.edit(nodeId, 'new value');
```

* `dump` returns the host's actual native node tree.
* `screenshot` asks the host to render its window to a PNG.
* `emit` synthesizes an event without optimistic local state.
* `edit` performs a real optimistic edit and exercises sequence acknowledgements.

Dump and screenshot requests time out rather than hanging forever. Screenshot failures return an error response and do not leave a successful-looking path.

## Interpret evidence precisely [#interpret-evidence-precisely]

A native tree dump proves materialization and props. An event assertion proves bridge behavior. A host-rendered PNG proves visible window content. None of these alone proves every popup layer, focus transition, or accessibility interaction.

---

# App shell and navigation

> Build native menus, toolbars, split views, and tab navigation.

Canonical: https://natui.dev/docs/components/app-shell-navigation

## MenuBar [#menubar]

Defines the application menu bar from serializable `MenuSpec` data. It must be a direct child of the React root.

### MenuBarProps

The application menu bar. Non-visual: must be a direct child of the root;
hosts hoist it to NSApp.mainMenu / a WinUI MenuBar row. Hosts never emit
select for disabled items, dividers, or submenu parents.

| Property | Type | Required | Description |
| --- | --- | --- | --- |
| `menus` | `MenuSpec[]` | Yes |  |
| `onSelect` | `((id: string) => void) \| undefined` | No |  |
| `key` | `string \| number \| undefined` | No |  |

```tsx
<MenuBar
  menus={[
    {
      id: 'file',
      label: 'File',
      items: [{ id: 'new', label: 'New', shortcut: 'cmd+n' }],
    },
  ]}
  onSelect={(id) => handleCommand(id)}
/>
```

macOS prepends its standard application menu. Command-role items such as `copy`, `paste`, and `quit` invoke platform commands and do not emit `onSelect`. The `about` role opens the standard About panel on macOS and is inert on Windows.

## Toolbar [#toolbar]

Defines native window toolbar items from `ToolbarItemSpec[]`. It must be a direct root child.

### ToolbarProps

The window toolbar (NSToolbar unified style / WinUI CommandBar).
Non-visual: must be a direct child of the root. Search items are
uncontrolled on the wire: text fires onSearch and is never echoed back.

| Property | Type | Required | Description |
| --- | --- | --- | --- |
| `items` | `ToolbarItemSpec[]` | Yes |  |
| `onAction` | `((id: string) => void) \| undefined` | No |  |
| `onSearch` | `((value: string) => void) \| undefined` | No |  |
| `key` | `string \| number \| undefined` | No |  |

```tsx
<Toolbar
  items={[
    { type: 'button', id: 'add', label: 'Add', systemImage: 'plus' },
    { type: 'flexibleSpace' },
    { type: 'search', id: 'search', placeholder: 'Filter' },
  ]}
  onAction={handleAction}
  onSearch={setQuery}
/>
```

Toolbar search text is host-local and reported through `onSearch`. Both hosts
preserve a surviving search item's text and focus across prop updates.

## SplitView, Sidebar, and Detail [#splitview-sidebar-and-detail]

`SplitView` routes `Sidebar` and `Detail` children into native navigation
slots. Use exactly one of each.

### SplitViewProps

Two-pane navigation split. Children are routed by kind: the first Sidebar
child fills the sidebar column, the first Detail child the detail column
(order-independent; extras are ignored with a warning). `value` optionally
controls sidebar visibility.

| Property | Type | Required | Description |
| --- | --- | --- | --- |
| `children` | `ReactNode` | No |  |
| `value` | `"all" \| "detailOnly" \| undefined` | No | Controlled sidebar visibility. SplitView is always controlled on the wire: there is no host-local visibility state, so an app that omits `value` still receives change events for user collapses, but any later re-render restores the sidebar. Provide `value` + `onChange` to keep it. |
| `sidebarWidth` | `number \| undefined` | No |  |
| `minSidebarWidth` | `number \| undefined` | No |  |
| `maxSidebarWidth` | `number \| undefined` | No |  |
| `onChange` | `((value: "all" \| "detailOnly") => void) \| undefined` | No |  |
| `padding` | `number \| EdgeInsets \| undefined` | No |  |
| `background` | `string \| undefined` | No |  |
| `cornerRadius` | `number \| undefined` | No |  |
| `frame` | `Frame \| undefined` | No |  |
| `opacity` | `number \| undefined` | No |  |
| `disabled` | `boolean \| undefined` | No |  |
| `hidden` | `boolean \| undefined` | No |  |
| `color` | `string \| undefined` | No | Foreground color. |
| `help` | `string \| undefined` | No | Tooltip. |
| `tag` | `string \| undefined` | No | Stable row identity for selectable containers (List/Table selection). A selectable List reports and receives selection as its rows' tags. |
| `badge` | `string \| number \| undefined` | No | Badge shown on Tab items and List rows (counts, short strings). |
| `accessibilityLabel` | `string \| undefined` | No | Assistive-tech label (VoiceOver / Narrator). |
| `accessibilityHint` | `string \| undefined` | No | Assistive-tech hint describing the result of activating the element. |
| `accessibilityIdentifier` | `string \| undefined` | No | Stable identifier for UI automation (AX identifier / AutomationId). |
| `key` | `string \| number \| undefined` | No |  |

### SidebarProps


| Property | Type | Required | Description |
| --- | --- | --- | --- |
| `children` | `ReactNode` | No |  |
| `padding` | `number \| EdgeInsets \| undefined` | No |  |
| `background` | `string \| undefined` | No |  |
| `cornerRadius` | `number \| undefined` | No |  |
| `frame` | `Frame \| undefined` | No |  |
| `opacity` | `number \| undefined` | No |  |
| `disabled` | `boolean \| undefined` | No |  |
| `hidden` | `boolean \| undefined` | No |  |
| `color` | `string \| undefined` | No | Foreground color. |
| `help` | `string \| undefined` | No | Tooltip. |
| `tag` | `string \| undefined` | No | Stable row identity for selectable containers (List/Table selection). A selectable List reports and receives selection as its rows' tags. |
| `badge` | `string \| number \| undefined` | No | Badge shown on Tab items and List rows (counts, short strings). |
| `accessibilityLabel` | `string \| undefined` | No | Assistive-tech label (VoiceOver / Narrator). |
| `accessibilityHint` | `string \| undefined` | No | Assistive-tech hint describing the result of activating the element. |
| `accessibilityIdentifier` | `string \| undefined` | No | Stable identifier for UI automation (AX identifier / AutomationId). |
| `key` | `string \| number \| undefined` | No |  |

### DetailProps


| Property | Type | Required | Description |
| --- | --- | --- | --- |
| `children` | `ReactNode` | No |  |
| `padding` | `number \| EdgeInsets \| undefined` | No |  |
| `background` | `string \| undefined` | No |  |
| `cornerRadius` | `number \| undefined` | No |  |
| `frame` | `Frame \| undefined` | No |  |
| `opacity` | `number \| undefined` | No |  |
| `disabled` | `boolean \| undefined` | No |  |
| `hidden` | `boolean \| undefined` | No |  |
| `color` | `string \| undefined` | No | Foreground color. |
| `help` | `string \| undefined` | No | Tooltip. |
| `tag` | `string \| undefined` | No | Stable row identity for selectable containers (List/Table selection). A selectable List reports and receives selection as its rows' tags. |
| `badge` | `string \| number \| undefined` | No | Badge shown on Tab items and List rows (counts, short strings). |
| `accessibilityLabel` | `string \| undefined` | No | Assistive-tech label (VoiceOver / Narrator). |
| `accessibilityHint` | `string \| undefined` | No | Assistive-tech hint describing the result of activating the element. |
| `accessibilityIdentifier` | `string \| undefined` | No | Stable identifier for UI automation (AX identifier / AutomationId). |
| `key` | `string \| number \| undefined` | No |  |

```tsx
<SplitView value={visibility} onChange={setVisibility} sidebarWidth={220}>
  <Sidebar>{navigation}</Sidebar>
  <Detail>{content}</Detail>
</SplitView>
```

Use `value="all"` or `value="detailOnly"` to control visibility. Native
visibility controls report changes through `onChange`. `sidebarWidth`,
`minSidebarWidth`, and `maxSidebarWidth` constrain the sidebar.

## TabView and Tab [#tabview-and-tab]

### TabViewProps

Controlled tab container; children are Tab elements. Tab clicks are optimistic.

| Property | Type | Required | Description |
| --- | --- | --- | --- |
| `children` | `ReactNode` | No |  |
| `value` | `string` | Yes | The selected Tab's `id`. |
| `onChange` | `((id: string) => void) \| undefined` | No |  |
| `padding` | `number \| EdgeInsets \| undefined` | No |  |
| `background` | `string \| undefined` | No |  |
| `cornerRadius` | `number \| undefined` | No |  |
| `frame` | `Frame \| undefined` | No |  |
| `opacity` | `number \| undefined` | No |  |
| `disabled` | `boolean \| undefined` | No |  |
| `hidden` | `boolean \| undefined` | No |  |
| `color` | `string \| undefined` | No | Foreground color. |
| `help` | `string \| undefined` | No | Tooltip. |
| `tag` | `string \| undefined` | No | Stable row identity for selectable containers (List/Table selection). A selectable List reports and receives selection as its rows' tags. |
| `badge` | `string \| number \| undefined` | No | Badge shown on Tab items and List rows (counts, short strings). |
| `accessibilityLabel` | `string \| undefined` | No | Assistive-tech label (VoiceOver / Narrator). |
| `accessibilityHint` | `string \| undefined` | No | Assistive-tech hint describing the result of activating the element. |
| `accessibilityIdentifier` | `string \| undefined` | No | Stable identifier for UI automation (AX identifier / AutomationId). |
| `key` | `string \| number \| undefined` | No |  |

### TabProps


| Property | Type | Required | Description |
| --- | --- | --- | --- |
| `id` | `string` | Yes |  |
| `title` | `string` | Yes |  |
| `systemImage` | `string \| undefined` | No |  |
| `children` | `ReactNode` | No |  |
| `padding` | `number \| EdgeInsets \| undefined` | No |  |
| `background` | `string \| undefined` | No |  |
| `cornerRadius` | `number \| undefined` | No |  |
| `frame` | `Frame \| undefined` | No |  |
| `opacity` | `number \| undefined` | No |  |
| `disabled` | `boolean \| undefined` | No |  |
| `hidden` | `boolean \| undefined` | No |  |
| `color` | `string \| undefined` | No | Foreground color. |
| `help` | `string \| undefined` | No | Tooltip. |
| `tag` | `string \| undefined` | No | Stable row identity for selectable containers (List/Table selection). A selectable List reports and receives selection as its rows' tags. |
| `badge` | `string \| number \| undefined` | No | Badge shown on Tab items and List rows (counts, short strings). |
| `accessibilityLabel` | `string \| undefined` | No | Assistive-tech label (VoiceOver / Narrator). |
| `accessibilityHint` | `string \| undefined` | No | Assistive-tech hint describing the result of activating the element. |
| `accessibilityIdentifier` | `string \| undefined` | No | Stable identifier for UI automation (AX identifier / AutomationId). |
| `key` | `string \| number \| undefined` | No |  |

```tsx
<TabView value={tab} onChange={setTab}>
  <Tab id="overview" title="Overview" systemImage="info.circle">
    <Text>Summary</Text>
  </Tab>
  <Tab id="settings" title="Settings" badge={2}>
    <Text>Preferences</Text>
  </Tab>
</TabView>
```

`TabView` is controlled by a child `Tab` id. A tab click updates native
selection optimistically, then reports the id through `onChange`. Tab titles,
system images, and badges render on both hosts.

## Verification note [#verification-note]

These seven app-shell kinds are exercised by the kitchen-sink real-window
suite on macOS and Windows.

---

# Content components

> Present native text, symbols, progress, links, and icon-label pairs.

Canonical: https://natui.dev/docs/components/content

## Text [#text]

Renders native text with semantic font styles, optional point size, weight, emphasis, monospacing, color, and line limits.

### TextProps


| Property | Type | Required | Description |
| --- | --- | --- | --- |
| `children` | `ReactNode` | No |  |
| `font` | `FontStyle \| undefined` | No |  |
| `size` | `number \| undefined` | No | Point size; when set, a system font of this size replaces `font` (weight still applies). |
| `weight` | `"regular" \| "medium" \| "semibold" \| "bold" \| undefined` | No |  |
| `italic` | `boolean \| undefined` | No |  |
| `strikethrough` | `boolean \| undefined` | No |  |
| `monospaced` | `boolean \| undefined` | No |  |
| `lineLimit` | `number \| undefined` | No |  |
| `padding` | `number \| EdgeInsets \| undefined` | No |  |
| `background` | `string \| undefined` | No |  |
| `cornerRadius` | `number \| undefined` | No |  |
| `frame` | `Frame \| undefined` | No |  |
| `opacity` | `number \| undefined` | No |  |
| `disabled` | `boolean \| undefined` | No |  |
| `hidden` | `boolean \| undefined` | No |  |
| `color` | `string \| undefined` | No | Foreground color. |
| `help` | `string \| undefined` | No | Tooltip. |
| `tag` | `string \| undefined` | No | Stable row identity for selectable containers (List/Table selection). A selectable List reports and receives selection as its rows' tags. |
| `badge` | `string \| number \| undefined` | No | Badge shown on Tab items and List rows (counts, short strings). |
| `accessibilityLabel` | `string \| undefined` | No | Assistive-tech label (VoiceOver / Narrator). |
| `accessibilityHint` | `string \| undefined` | No | Assistive-tech hint describing the result of activating the element. |
| `accessibilityIdentifier` | `string \| undefined` | No | Stable identifier for UI automation (AX identifier / AutomationId). |
| `key` | `string \| number \| undefined` | No |  |

```tsx
<Text font="title2" weight="semibold" lineLimit={2}>
  Native text
</Text>
```

`font` accepts `largeTitle`, `title`, `title2`, `title3`, `headline`, `body`, `callout`, or `caption`. Setting `size` replaces the semantic font size while preserving `weight`.

## Image [#image]

Renders a system symbol with `systemName` and optional `size`.

### ImageProps


| Property | Type | Required | Description |
| --- | --- | --- | --- |
| `systemName` | `string` | Yes | SF Symbols name on macOS; mapped to Segoe Fluent glyphs on Windows. |
| `size` | `number \| undefined` | No |  |
| `padding` | `number \| EdgeInsets \| undefined` | No |  |
| `background` | `string \| undefined` | No |  |
| `cornerRadius` | `number \| undefined` | No |  |
| `frame` | `Frame \| undefined` | No |  |
| `opacity` | `number \| undefined` | No |  |
| `disabled` | `boolean \| undefined` | No |  |
| `hidden` | `boolean \| undefined` | No |  |
| `color` | `string \| undefined` | No | Foreground color. |
| `help` | `string \| undefined` | No | Tooltip. |
| `tag` | `string \| undefined` | No | Stable row identity for selectable containers (List/Table selection). A selectable List reports and receives selection as its rows' tags. |
| `badge` | `string \| number \| undefined` | No | Badge shown on Tab items and List rows (counts, short strings). |
| `accessibilityLabel` | `string \| undefined` | No | Assistive-tech label (VoiceOver / Narrator). |
| `accessibilityHint` | `string \| undefined` | No | Assistive-tech hint describing the result of activating the element. |
| `accessibilityIdentifier` | `string \| undefined` | No | Stable identifier for UI automation (AX identifier / AutomationId). |
| `key` | `string \| number \| undefined` | No |  |

```tsx
<Image systemName="star" size={18} accessibilityLabel="Favorite" />
```

Names are SF Symbols on macOS. Windows maps a supported subset to Segoe Fluent glyphs, so symbols may differ or fall back.

## ProgressView [#progressview]

Pass a value from `0` to `1` for determinate progress. Omit `value` for an indeterminate indicator.

### ProgressViewProps


| Property | Type | Required | Description |
| --- | --- | --- | --- |
| `value` | `number \| undefined` | No | 0..1. Omit for an indeterminate spinner. |
| `padding` | `number \| EdgeInsets \| undefined` | No |  |
| `background` | `string \| undefined` | No |  |
| `cornerRadius` | `number \| undefined` | No |  |
| `frame` | `Frame \| undefined` | No |  |
| `opacity` | `number \| undefined` | No |  |
| `disabled` | `boolean \| undefined` | No |  |
| `hidden` | `boolean \| undefined` | No |  |
| `color` | `string \| undefined` | No | Foreground color. |
| `help` | `string \| undefined` | No | Tooltip. |
| `tag` | `string \| undefined` | No | Stable row identity for selectable containers (List/Table selection). A selectable List reports and receives selection as its rows' tags. |
| `badge` | `string \| number \| undefined` | No | Badge shown on Tab items and List rows (counts, short strings). |
| `accessibilityLabel` | `string \| undefined` | No | Assistive-tech label (VoiceOver / Narrator). |
| `accessibilityHint` | `string \| undefined` | No | Assistive-tech hint describing the result of activating the element. |
| `accessibilityIdentifier` | `string \| undefined` | No | Stable identifier for UI automation (AX identifier / AutomationId). |
| `key` | `string \| number \| undefined` | No |  |

```tsx
<ProgressView value={completed / total} frame={{ width: 240 }} />
```

## Link [#link]

Opens `url` in the system browser. Children form the visible label, and `onPress` can observe activation.

### LinkProps

Opens `url` in the system browser; children form the link label.

| Property | Type | Required | Description |
| --- | --- | --- | --- |
| `children` | `ReactNode` | No |  |
| `url` | `string` | Yes |  |
| `onPress` | `(() => void) \| undefined` | No |  |
| `padding` | `number \| EdgeInsets \| undefined` | No |  |
| `background` | `string \| undefined` | No |  |
| `cornerRadius` | `number \| undefined` | No |  |
| `frame` | `Frame \| undefined` | No |  |
| `opacity` | `number \| undefined` | No |  |
| `disabled` | `boolean \| undefined` | No |  |
| `hidden` | `boolean \| undefined` | No |  |
| `color` | `string \| undefined` | No | Foreground color. |
| `help` | `string \| undefined` | No | Tooltip. |
| `tag` | `string \| undefined` | No | Stable row identity for selectable containers (List/Table selection). A selectable List reports and receives selection as its rows' tags. |
| `badge` | `string \| number \| undefined` | No | Badge shown on Tab items and List rows (counts, short strings). |
| `accessibilityLabel` | `string \| undefined` | No | Assistive-tech label (VoiceOver / Narrator). |
| `accessibilityHint` | `string \| undefined` | No | Assistive-tech hint describing the result of activating the element. |
| `accessibilityIdentifier` | `string \| undefined` | No | Stable identifier for UI automation (AX identifier / AutomationId). |
| `key` | `string \| number \| undefined` | No |  |

```tsx
<Link url="https://github.com/floklein/natui">
  Project repository
</Link>
```

## Label [#label]

Combines a system symbol with child text.

### LabelProps

Icon + title pair; children form the title.

| Property | Type | Required | Description |
| --- | --- | --- | --- |
| `children` | `ReactNode` | No |  |
| `systemImage` | `string` | Yes |  |
| `padding` | `number \| EdgeInsets \| undefined` | No |  |
| `background` | `string \| undefined` | No |  |
| `cornerRadius` | `number \| undefined` | No |  |
| `frame` | `Frame \| undefined` | No |  |
| `opacity` | `number \| undefined` | No |  |
| `disabled` | `boolean \| undefined` | No |  |
| `hidden` | `boolean \| undefined` | No |  |
| `color` | `string \| undefined` | No | Foreground color. |
| `help` | `string \| undefined` | No | Tooltip. |
| `tag` | `string \| undefined` | No | Stable row identity for selectable containers (List/Table selection). A selectable List reports and receives selection as its rows' tags. |
| `badge` | `string \| number \| undefined` | No | Badge shown on Tab items and List rows (counts, short strings). |
| `accessibilityLabel` | `string \| undefined` | No | Assistive-tech label (VoiceOver / Narrator). |
| `accessibilityHint` | `string \| undefined` | No | Assistive-tech hint describing the result of activating the element. |
| `accessibilityIdentifier` | `string \| undefined` | No | Stable identifier for UI automation (AX identifier / AutomationId). |
| `key` | `string \| number \| undefined` | No |  |

```tsx
<Label systemImage="calendar" badge={3}>Upcoming</Label>
```

Symbol mapping follows the same platform rules as `Image`.

---

# Data components

> Group content, display sortable tables, and reveal controlled detail.

Canonical: https://natui.dev/docs/components/data

## Section [#section]

Groups children under optional `header` and `footer` text.

### SectionProps


| Property | Type | Required | Description |
| --- | --- | --- | --- |
| `header` | `string \| undefined` | No |  |
| `footer` | `string \| undefined` | No |  |
| `children` | `ReactNode` | No |  |
| `padding` | `number \| EdgeInsets \| undefined` | No |  |
| `background` | `string \| undefined` | No |  |
| `cornerRadius` | `number \| undefined` | No |  |
| `frame` | `Frame \| undefined` | No |  |
| `opacity` | `number \| undefined` | No |  |
| `disabled` | `boolean \| undefined` | No |  |
| `hidden` | `boolean \| undefined` | No |  |
| `color` | `string \| undefined` | No | Foreground color. |
| `help` | `string \| undefined` | No | Tooltip. |
| `tag` | `string \| undefined` | No | Stable row identity for selectable containers (List/Table selection). A selectable List reports and receives selection as its rows' tags. |
| `badge` | `string \| number \| undefined` | No | Badge shown on Tab items and List rows (counts, short strings). |
| `accessibilityLabel` | `string \| undefined` | No | Assistive-tech label (VoiceOver / Narrator). |
| `accessibilityHint` | `string \| undefined` | No | Assistive-tech hint describing the result of activating the element. |
| `accessibilityIdentifier` | `string \| undefined` | No | Stable identifier for UI automation (AX identifier / AutomationId). |
| `key` | `string \| number \| undefined` | No |  |

```tsx
<Section header="Identity" footer="All fields are required.">
  <TextField value={name} onChange={setName} />
</Section>
```

Sections can appear in lists or ordinary layout containers. Rows nested inside
a list section participate in the outer list's controlled selection.

## Table [#table]

Tables receive serializable columns and rows. Cells are strings keyed by column.

### TableProps

A sortable, selectable table with data-driven columns and string cells.
The host never sorts: a header click emits onSortChange (request
semantics); the app re-sorts `rows` and echoes the new `sort`.

| Property | Type | Required | Description |
| --- | --- | --- | --- |
| `columns` | `TableColumnSpec[]` | Yes |  |
| `rows` | `TableRowSpec[]` | Yes |  |
| `value` | `string \| string[] \| null \| undefined` | No | Controlled selection over row ids; present (even null) = selectable. |
| `selectionMode` | `"single" \| "multiple" \| undefined` | No |  |
| `sort` | `SortDescriptor \| undefined` | No |  |
| `onChange` | `((value: string \| string[] \| null) => void) \| undefined` | No |  |
| `onSortChange` | `((sort: SortDescriptor) => void) \| undefined` | No |  |
| `padding` | `number \| EdgeInsets \| undefined` | No |  |
| `background` | `string \| undefined` | No |  |
| `cornerRadius` | `number \| undefined` | No |  |
| `frame` | `Frame \| undefined` | No |  |
| `opacity` | `number \| undefined` | No |  |
| `disabled` | `boolean \| undefined` | No |  |
| `hidden` | `boolean \| undefined` | No |  |
| `color` | `string \| undefined` | No | Foreground color. |
| `help` | `string \| undefined` | No | Tooltip. |
| `tag` | `string \| undefined` | No | Stable row identity for selectable containers (List/Table selection). A selectable List reports and receives selection as its rows' tags. |
| `badge` | `string \| number \| undefined` | No | Badge shown on Tab items and List rows (counts, short strings). |
| `accessibilityLabel` | `string \| undefined` | No | Assistive-tech label (VoiceOver / Narrator). |
| `accessibilityHint` | `string \| undefined` | No | Assistive-tech hint describing the result of activating the element. |
| `accessibilityIdentifier` | `string \| undefined` | No | Stable identifier for UI automation (AX identifier / AutomationId). |
| `key` | `string \| number \| undefined` | No |  |

```tsx
<Table
  columns={[
    { key: 'name', label: 'Name' },
    { key: 'status', label: 'Status', sortable: false },
  ]}
  rows={[
    { id: 'one', cells: { name: 'Aurora', status: 'Active' } },
  ]}
  value={selection}
  selectionMode="single"
  sort={sort}
  onChange={setSelection}
  onSortChange={setSort}
/>
```

The host never sorts rows. A header interaction requests a new `SortDescriptor`; the application sorts its data, provides the reordered rows, and echoes the descriptor.

On macOS 14.0 through 14.3, NatUI uses a list-based table fallback because the dynamic table API requires macOS 14.4.

## DisclosureGroup [#disclosuregroup]

Shows or hides child content using a controlled Boolean value.

### DisclosureGroupProps

Always-controlled disclosure; `value` is the expanded state.

| Property | Type | Required | Description |
| --- | --- | --- | --- |
| `label` | `string` | Yes |  |
| `value` | `boolean` | Yes |  |
| `onChange` | `((expanded: boolean) => void) \| undefined` | No |  |
| `children` | `ReactNode` | No |  |
| `padding` | `number \| EdgeInsets \| undefined` | No |  |
| `background` | `string \| undefined` | No |  |
| `cornerRadius` | `number \| undefined` | No |  |
| `frame` | `Frame \| undefined` | No |  |
| `opacity` | `number \| undefined` | No |  |
| `disabled` | `boolean \| undefined` | No |  |
| `hidden` | `boolean \| undefined` | No |  |
| `color` | `string \| undefined` | No | Foreground color. |
| `help` | `string \| undefined` | No | Tooltip. |
| `tag` | `string \| undefined` | No | Stable row identity for selectable containers (List/Table selection). A selectable List reports and receives selection as its rows' tags. |
| `badge` | `string \| number \| undefined` | No | Badge shown on Tab items and List rows (counts, short strings). |
| `accessibilityLabel` | `string \| undefined` | No | Assistive-tech label (VoiceOver / Narrator). |
| `accessibilityHint` | `string \| undefined` | No | Assistive-tech hint describing the result of activating the element. |
| `accessibilityIdentifier` | `string \| undefined` | No | Stable identifier for UI automation (AX identifier / AutomationId). |
| `key` | `string \| number \| undefined` | No |  |

```tsx
<DisclosureGroup label="Details" value={expanded} onChange={setExpanded}>
  <Text>Additional information</Text>
</DisclosureGroup>
```

Disclosure state is always controlled. If React does not accept a native expansion change, NatUI corrects the host back to the current prop.

---

# Components

> Browse all 37 typed NatUI host components by capability.

Canonical: https://natui.dev/docs/components

Every NatUI component is a typed React function component whose element kind is materialized by the native host. Components accept documented JSON-compatible props and React event handlers.

| Group                                                             | Components                                                                                                |
| ----------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------- |
| [Layout](/docs/components/layout)                                 | `VStack`, `HStack`, `ZStack`, `Spacer`, `Divider`, `ScrollView`, `List`                                   |
| [Content](/docs/components/content)                               | `Text`, `Image`, `ProgressView`, `Link`, `Label`                                                          |
| [Inputs](/docs/components/inputs)                                 | `Button`, `TextField`, `Toggle`, `Slider`, `Picker`, `SearchField`, `DatePicker`, `Stepper`, `TextEditor` |
| [App shell and navigation](/docs/components/app-shell-navigation) | `MenuBar`, `Toolbar`, `SplitView`, `Sidebar`, `Detail`, `TabView`, `Tab`                                  |
| [Menus](/docs/components/menus)                                   | `Menu`, `ContextMenu`                                                                                     |
| [Presentation](/docs/components/presentation)                     | `Sheet`, `Alert`, `Popover`, `PopoverContent`                                                             |
| [Data](/docs/components/data)                                     | `Section`, `Table`, `DisclosureGroup`                                                                     |

The catalog contains exactly 37 public host components from `packages/natui/src/components.ts`.

## Shared behavior [#shared-behavior]

Most components accept [common props](/docs/guides/common-props) for sizing, padding, color, visibility, selection identity, badges, tooltips, and accessibility.

Native layout is intentional. A component maps to the closest platform control instead of reproducing pixel-identical output across operating systems.

---

# Input components

> Build controlled native buttons, fields, toggles, pickers, and editors.

Canonical: https://natui.dev/docs/components/inputs

NatUI inputs are controlled React components. Pass the current `value` and update it in the corresponding event handler.

## Button [#button]

### ButtonProps


| Property | Type | Required | Description |
| --- | --- | --- | --- |
| `children` | `ReactNode` | No |  |
| `onPress` | `(() => void) \| undefined` | No |  |
| `variant` | `"automatic" \| "bordered" \| "prominent" \| "plain" \| "link" \| undefined` | No |  |
| `role` | `"destructive" \| "cancel" \| undefined` | No |  |
| `padding` | `number \| EdgeInsets \| undefined` | No |  |
| `background` | `string \| undefined` | No |  |
| `cornerRadius` | `number \| undefined` | No |  |
| `frame` | `Frame \| undefined` | No |  |
| `opacity` | `number \| undefined` | No |  |
| `disabled` | `boolean \| undefined` | No |  |
| `hidden` | `boolean \| undefined` | No |  |
| `color` | `string \| undefined` | No | Foreground color. |
| `help` | `string \| undefined` | No | Tooltip. |
| `tag` | `string \| undefined` | No | Stable row identity for selectable containers (List/Table selection). A selectable List reports and receives selection as its rows' tags. |
| `badge` | `string \| number \| undefined` | No | Badge shown on Tab items and List rows (counts, short strings). |
| `accessibilityLabel` | `string \| undefined` | No | Assistive-tech label (VoiceOver / Narrator). |
| `accessibilityHint` | `string \| undefined` | No | Assistive-tech hint describing the result of activating the element. |
| `accessibilityIdentifier` | `string \| undefined` | No | Stable identifier for UI automation (AX identifier / AutomationId). |
| `key` | `string \| number \| undefined` | No |  |

```tsx
<Button variant="prominent" onPress={save}>Save</Button>
```

Variants are `automatic`, `bordered`, `prominent`, `plain`, and `link`. Roles
are `destructive` and `cancel`. Windows maps prominent, plain, and link to
their native WinUI styles, while automatic and bordered use the standard
button appearance.

## TextField [#textfield]

### TextFieldProps


| Property | Type | Required | Description |
| --- | --- | --- | --- |
| `value` | `string` | Yes |  |
| `placeholder` | `string \| undefined` | No |  |
| `secure` | `boolean \| undefined` | No |  |
| `onChange` | `((value: string) => void) \| undefined` | No |  |
| `onSubmit` | `((value: string) => void) \| undefined` | No |  |
| `padding` | `number \| EdgeInsets \| undefined` | No |  |
| `background` | `string \| undefined` | No |  |
| `cornerRadius` | `number \| undefined` | No |  |
| `frame` | `Frame \| undefined` | No |  |
| `opacity` | `number \| undefined` | No |  |
| `disabled` | `boolean \| undefined` | No |  |
| `hidden` | `boolean \| undefined` | No |  |
| `color` | `string \| undefined` | No | Foreground color. |
| `help` | `string \| undefined` | No | Tooltip. |
| `tag` | `string \| undefined` | No | Stable row identity for selectable containers (List/Table selection). A selectable List reports and receives selection as its rows' tags. |
| `badge` | `string \| number \| undefined` | No | Badge shown on Tab items and List rows (counts, short strings). |
| `accessibilityLabel` | `string \| undefined` | No | Assistive-tech label (VoiceOver / Narrator). |
| `accessibilityHint` | `string \| undefined` | No | Assistive-tech hint describing the result of activating the element. |
| `accessibilityIdentifier` | `string \| undefined` | No | Stable identifier for UI automation (AX identifier / AutomationId). |
| `key` | `string \| number \| undefined` | No |  |

```tsx
<TextField
  value={email}
  placeholder="Email"
  onChange={setEmail}
  onSubmit={submit}
/>
```

Set `secure` for protected entry. Changing it after creation swaps the native
control while preserving the React node.

## Toggle [#toggle]

### ToggleProps


| Property | Type | Required | Description |
| --- | --- | --- | --- |
| `children` | `ReactNode` | No |  |
| `value` | `boolean` | Yes |  |
| `style` | `"automatic" \| "checkbox" \| "switch" \| undefined` | No | 'automatic' is the platform default (checkbox on macOS, checkbox on Windows). |
| `onChange` | `((value: boolean) => void) \| undefined` | No |  |
| `padding` | `number \| EdgeInsets \| undefined` | No |  |
| `background` | `string \| undefined` | No |  |
| `cornerRadius` | `number \| undefined` | No |  |
| `frame` | `Frame \| undefined` | No |  |
| `opacity` | `number \| undefined` | No |  |
| `disabled` | `boolean \| undefined` | No |  |
| `hidden` | `boolean \| undefined` | No |  |
| `color` | `string \| undefined` | No | Foreground color. |
| `help` | `string \| undefined` | No | Tooltip. |
| `tag` | `string \| undefined` | No | Stable row identity for selectable containers (List/Table selection). A selectable List reports and receives selection as its rows' tags. |
| `badge` | `string \| number \| undefined` | No | Badge shown on Tab items and List rows (counts, short strings). |
| `accessibilityLabel` | `string \| undefined` | No | Assistive-tech label (VoiceOver / Narrator). |
| `accessibilityHint` | `string \| undefined` | No | Assistive-tech hint describing the result of activating the element. |
| `accessibilityIdentifier` | `string \| undefined` | No | Stable identifier for UI automation (AX identifier / AutomationId). |
| `key` | `string \| number \| undefined` | No |  |

```tsx
<Toggle value={enabled} style="switch" onChange={setEnabled}>
  Notifications
</Toggle>
```

Styles are `automatic`, `checkbox`, and `switch`. Style changes replace the
native control while preserving the React node.

## Slider [#slider]

### SliderProps


| Property | Type | Required | Description |
| --- | --- | --- | --- |
| `value` | `number` | Yes |  |
| `min` | `number \| undefined` | No |  |
| `max` | `number \| undefined` | No |  |
| `step` | `number \| undefined` | No |  |
| `onChange` | `((value: number) => void) \| undefined` | No |  |
| `padding` | `number \| EdgeInsets \| undefined` | No |  |
| `background` | `string \| undefined` | No |  |
| `cornerRadius` | `number \| undefined` | No |  |
| `frame` | `Frame \| undefined` | No |  |
| `opacity` | `number \| undefined` | No |  |
| `disabled` | `boolean \| undefined` | No |  |
| `hidden` | `boolean \| undefined` | No |  |
| `color` | `string \| undefined` | No | Foreground color. |
| `help` | `string \| undefined` | No | Tooltip. |
| `tag` | `string \| undefined` | No | Stable row identity for selectable containers (List/Table selection). A selectable List reports and receives selection as its rows' tags. |
| `badge` | `string \| number \| undefined` | No | Badge shown on Tab items and List rows (counts, short strings). |
| `accessibilityLabel` | `string \| undefined` | No | Assistive-tech label (VoiceOver / Narrator). |
| `accessibilityHint` | `string \| undefined` | No | Assistive-tech hint describing the result of activating the element. |
| `accessibilityIdentifier` | `string \| undefined` | No | Stable identifier for UI automation (AX identifier / AutomationId). |
| `key` | `string \| number \| undefined` | No |  |

```tsx
<Slider value={volume} min={0} max={100} step={1} onChange={setVolume} />
```

## Picker [#picker]

### PickerProps


| Property | Type | Required | Description |
| --- | --- | --- | --- |
| `value` | `string` | Yes |  |
| `options` | `PickerOption[]` | Yes |  |
| `label` | `string \| undefined` | No |  |
| `style` | `"automatic" \| "menu" \| "segmented" \| "radioGroup" \| undefined` | No | 'automatic' is the platform default (a dropdown menu). |
| `onChange` | `((value: string) => void) \| undefined` | No |  |
| `padding` | `number \| EdgeInsets \| undefined` | No |  |
| `background` | `string \| undefined` | No |  |
| `cornerRadius` | `number \| undefined` | No |  |
| `frame` | `Frame \| undefined` | No |  |
| `opacity` | `number \| undefined` | No |  |
| `disabled` | `boolean \| undefined` | No |  |
| `hidden` | `boolean \| undefined` | No |  |
| `color` | `string \| undefined` | No | Foreground color. |
| `help` | `string \| undefined` | No | Tooltip. |
| `tag` | `string \| undefined` | No | Stable row identity for selectable containers (List/Table selection). A selectable List reports and receives selection as its rows' tags. |
| `badge` | `string \| number \| undefined` | No | Badge shown on Tab items and List rows (counts, short strings). |
| `accessibilityLabel` | `string \| undefined` | No | Assistive-tech label (VoiceOver / Narrator). |
| `accessibilityHint` | `string \| undefined` | No | Assistive-tech hint describing the result of activating the element. |
| `accessibilityIdentifier` | `string \| undefined` | No | Stable identifier for UI automation (AX identifier / AutomationId). |
| `key` | `string \| number \| undefined` | No |  |

```tsx
<Picker
  label="Size"
  value={size}
  options={[
    { value: 's', label: 'Small' },
    { value: 'm', label: 'Medium' },
  ]}
  style="segmented"
  onChange={setSize}
/>
```

Styles are `automatic`, `menu`, `segmented`, and `radioGroup`. Style changes
replace the native control while preserving the React node.

## SearchField [#searchfield]

Provides controlled text with optional `placeholder`, `onChange`, and `onSubmit`.

### SearchFieldProps


| Property | Type | Required | Description |
| --- | --- | --- | --- |
| `value` | `string` | Yes |  |
| `placeholder` | `string \| undefined` | No |  |
| `onChange` | `((value: string) => void) \| undefined` | No |  |
| `onSubmit` | `((value: string) => void) \| undefined` | No |  |
| `padding` | `number \| EdgeInsets \| undefined` | No |  |
| `background` | `string \| undefined` | No |  |
| `cornerRadius` | `number \| undefined` | No |  |
| `frame` | `Frame \| undefined` | No |  |
| `opacity` | `number \| undefined` | No |  |
| `disabled` | `boolean \| undefined` | No |  |
| `hidden` | `boolean \| undefined` | No |  |
| `color` | `string \| undefined` | No | Foreground color. |
| `help` | `string \| undefined` | No | Tooltip. |
| `tag` | `string \| undefined` | No | Stable row identity for selectable containers (List/Table selection). A selectable List reports and receives selection as its rows' tags. |
| `badge` | `string \| number \| undefined` | No | Badge shown on Tab items and List rows (counts, short strings). |
| `accessibilityLabel` | `string \| undefined` | No | Assistive-tech label (VoiceOver / Narrator). |
| `accessibilityHint` | `string \| undefined` | No | Assistive-tech hint describing the result of activating the element. |
| `accessibilityIdentifier` | `string \| undefined` | No | Stable identifier for UI automation (AX identifier / AutomationId). |
| `key` | `string \| number \| undefined` | No |  |

```tsx
<SearchField value={query} placeholder="Search" onChange={setQuery} />
```

## DatePicker [#datepicker]

Uses a local ISO value without a time zone:

### DatePickerProps

Date/time input. `value` is a LOCAL ISO string without a zone, shaped by
`displayedComponents`: 'YYYY-MM-DD' (date), 'HH:mm' (time), or
'YYYY-MM-DDTHH:mm' (dateTime). Hosts re-serialize canonically so a
round-trip is byte-identical.

| Property | Type | Required | Description |
| --- | --- | --- | --- |
| `value` | `string` | Yes |  |
| `displayedComponents` | `"date" \| "time" \| "dateTime" \| undefined` | No |  |
| `onChange` | `((value: string) => void) \| undefined` | No |  |
| `padding` | `number \| EdgeInsets \| undefined` | No |  |
| `background` | `string \| undefined` | No |  |
| `cornerRadius` | `number \| undefined` | No |  |
| `frame` | `Frame \| undefined` | No |  |
| `opacity` | `number \| undefined` | No |  |
| `disabled` | `boolean \| undefined` | No |  |
| `hidden` | `boolean \| undefined` | No |  |
| `color` | `string \| undefined` | No | Foreground color. |
| `help` | `string \| undefined` | No | Tooltip. |
| `tag` | `string \| undefined` | No | Stable row identity for selectable containers (List/Table selection). A selectable List reports and receives selection as its rows' tags. |
| `badge` | `string \| number \| undefined` | No | Badge shown on Tab items and List rows (counts, short strings). |
| `accessibilityLabel` | `string \| undefined` | No | Assistive-tech label (VoiceOver / Narrator). |
| `accessibilityHint` | `string \| undefined` | No | Assistive-tech hint describing the result of activating the element. |
| `accessibilityIdentifier` | `string \| undefined` | No | Stable identifier for UI automation (AX identifier / AutomationId). |
| `key` | `string \| number \| undefined` | No |  |

* `date`: `YYYY-MM-DD`
* `time`: `HH:mm`
* `dateTime`: `YYYY-MM-DDTHH:mm`

```tsx
<DatePicker value={due} displayedComponents="date" onChange={setDue} />
```

Windows uses native date and time controls, pairing them for `dateTime`.
All three modes parse and emit the canonical local ISO shape documented by
`DatePickerProps`.

## Stepper [#stepper]

### StepperProps


| Property | Type | Required | Description |
| --- | --- | --- | --- |
| `value` | `number` | Yes |  |
| `min` | `number \| undefined` | No |  |
| `max` | `number \| undefined` | No |  |
| `step` | `number \| undefined` | No |  |
| `onChange` | `((value: number) => void) \| undefined` | No |  |
| `padding` | `number \| EdgeInsets \| undefined` | No |  |
| `background` | `string \| undefined` | No |  |
| `cornerRadius` | `number \| undefined` | No |  |
| `frame` | `Frame \| undefined` | No |  |
| `opacity` | `number \| undefined` | No |  |
| `disabled` | `boolean \| undefined` | No |  |
| `hidden` | `boolean \| undefined` | No |  |
| `color` | `string \| undefined` | No | Foreground color. |
| `help` | `string \| undefined` | No | Tooltip. |
| `tag` | `string \| undefined` | No | Stable row identity for selectable containers (List/Table selection). A selectable List reports and receives selection as its rows' tags. |
| `badge` | `string \| number \| undefined` | No | Badge shown on Tab items and List rows (counts, short strings). |
| `accessibilityLabel` | `string \| undefined` | No | Assistive-tech label (VoiceOver / Narrator). |
| `accessibilityHint` | `string \| undefined` | No | Assistive-tech hint describing the result of activating the element. |
| `accessibilityIdentifier` | `string \| undefined` | No | Stable identifier for UI automation (AX identifier / AutomationId). |
| `key` | `string \| number \| undefined` | No |  |

```tsx
<Stepper value={quantity} min={1} max={10} step={1} onChange={setQuantity} />
```

## TextEditor [#texteditor]

Renders a multiline plain-text editor.

### TextEditorProps

Multiline plain-text editor.

| Property | Type | Required | Description |
| --- | --- | --- | --- |
| `value` | `string` | Yes |  |
| `onChange` | `((value: string) => void) \| undefined` | No |  |
| `padding` | `number \| EdgeInsets \| undefined` | No |  |
| `background` | `string \| undefined` | No |  |
| `cornerRadius` | `number \| undefined` | No |  |
| `frame` | `Frame \| undefined` | No |  |
| `opacity` | `number \| undefined` | No |  |
| `disabled` | `boolean \| undefined` | No |  |
| `hidden` | `boolean \| undefined` | No |  |
| `color` | `string \| undefined` | No | Foreground color. |
| `help` | `string \| undefined` | No | Tooltip. |
| `tag` | `string \| undefined` | No | Stable row identity for selectable containers (List/Table selection). A selectable List reports and receives selection as its rows' tags. |
| `badge` | `string \| number \| undefined` | No | Badge shown on Tab items and List rows (counts, short strings). |
| `accessibilityLabel` | `string \| undefined` | No | Assistive-tech label (VoiceOver / Narrator). |
| `accessibilityHint` | `string \| undefined` | No | Assistive-tech hint describing the result of activating the element. |
| `accessibilityIdentifier` | `string \| undefined` | No | Stable identifier for UI automation (AX identifier / AutomationId). |
| `key` | `string \| number \| undefined` | No |  |

```tsx
<TextEditor value={notes} onChange={setNotes} frame={{ height: 100 }} />
```

All controlled input kinds participate in NatUI's [sequence acknowledgement protocol](/docs/guides/controlled-state).

---

# Layout components

> Arrange native controls with stacks, scrolling, lists, spacing, and dividers.

Canonical: https://natui.dev/docs/components/layout

## VStack [#vstack]

Arranges children vertically. `spacing` controls the gap, and `alignment` accepts `leading`, `center`, or `trailing`.

### VStackProps


| Property | Type | Required | Description |
| --- | --- | --- | --- |
| `spacing` | `number \| undefined` | No |  |
| `alignment` | `"leading" \| "center" \| "trailing" \| undefined` | No |  |
| `children` | `ReactNode` | No |  |
| `padding` | `number \| EdgeInsets \| undefined` | No |  |
| `background` | `string \| undefined` | No |  |
| `cornerRadius` | `number \| undefined` | No |  |
| `frame` | `Frame \| undefined` | No |  |
| `opacity` | `number \| undefined` | No |  |
| `disabled` | `boolean \| undefined` | No |  |
| `hidden` | `boolean \| undefined` | No |  |
| `color` | `string \| undefined` | No | Foreground color. |
| `help` | `string \| undefined` | No | Tooltip. |
| `tag` | `string \| undefined` | No | Stable row identity for selectable containers (List/Table selection). A selectable List reports and receives selection as its rows' tags. |
| `badge` | `string \| number \| undefined` | No | Badge shown on Tab items and List rows (counts, short strings). |
| `accessibilityLabel` | `string \| undefined` | No | Assistive-tech label (VoiceOver / Narrator). |
| `accessibilityHint` | `string \| undefined` | No | Assistive-tech hint describing the result of activating the element. |
| `accessibilityIdentifier` | `string \| undefined` | No | Stable identifier for UI automation (AX identifier / AutomationId). |
| `key` | `string \| number \| undefined` | No |  |

```tsx
<VStack spacing={12} padding={20} alignment="leading">
  <Text font="headline">Account</Text>
  <TextField value={name} onChange={setName} />
</VStack>
```

## HStack [#hstack]

Arranges children horizontally. `alignment` accepts `top`, `center`, or `bottom`.

### HStackProps


| Property | Type | Required | Description |
| --- | --- | --- | --- |
| `spacing` | `number \| undefined` | No |  |
| `alignment` | `"center" \| "top" \| "bottom" \| undefined` | No |  |
| `children` | `ReactNode` | No |  |
| `padding` | `number \| EdgeInsets \| undefined` | No |  |
| `background` | `string \| undefined` | No |  |
| `cornerRadius` | `number \| undefined` | No |  |
| `frame` | `Frame \| undefined` | No |  |
| `opacity` | `number \| undefined` | No |  |
| `disabled` | `boolean \| undefined` | No |  |
| `hidden` | `boolean \| undefined` | No |  |
| `color` | `string \| undefined` | No | Foreground color. |
| `help` | `string \| undefined` | No | Tooltip. |
| `tag` | `string \| undefined` | No | Stable row identity for selectable containers (List/Table selection). A selectable List reports and receives selection as its rows' tags. |
| `badge` | `string \| number \| undefined` | No | Badge shown on Tab items and List rows (counts, short strings). |
| `accessibilityLabel` | `string \| undefined` | No | Assistive-tech label (VoiceOver / Narrator). |
| `accessibilityHint` | `string \| undefined` | No | Assistive-tech hint describing the result of activating the element. |
| `accessibilityIdentifier` | `string \| undefined` | No | Stable identifier for UI automation (AX identifier / AutomationId). |
| `key` | `string \| number \| undefined` | No |  |

```tsx
<HStack spacing={8} alignment="center">
  <Label systemImage="person">Profile</Label>
  <Spacer />
  <Button onPress={save}>Save</Button>
</HStack>
```

## ZStack [#zstack]

Overlays children in the same native layout region. On Windows it maps to a
grid that propagates flexible-space proposals through nested stacks.

### ZStackProps


| Property | Type | Required | Description |
| --- | --- | --- | --- |
| `children` | `ReactNode` | No |  |
| `padding` | `number \| EdgeInsets \| undefined` | No |  |
| `background` | `string \| undefined` | No |  |
| `cornerRadius` | `number \| undefined` | No |  |
| `frame` | `Frame \| undefined` | No |  |
| `opacity` | `number \| undefined` | No |  |
| `disabled` | `boolean \| undefined` | No |  |
| `hidden` | `boolean \| undefined` | No |  |
| `color` | `string \| undefined` | No | Foreground color. |
| `help` | `string \| undefined` | No | Tooltip. |
| `tag` | `string \| undefined` | No | Stable row identity for selectable containers (List/Table selection). A selectable List reports and receives selection as its rows' tags. |
| `badge` | `string \| number \| undefined` | No | Badge shown on Tab items and List rows (counts, short strings). |
| `accessibilityLabel` | `string \| undefined` | No | Assistive-tech label (VoiceOver / Narrator). |
| `accessibilityHint` | `string \| undefined` | No | Assistive-tech hint describing the result of activating the element. |
| `accessibilityIdentifier` | `string \| undefined` | No | Stable identifier for UI automation (AX identifier / AutomationId). |
| `key` | `string \| number \| undefined` | No |  |

```tsx
<ZStack frame={{ width: 240, height: 140 }}>
  <Image systemName="rectangle.fill" size={120} />
  <Text weight="bold">Overlay</Text>
</ZStack>
```

## Spacer [#spacer]

Consumes available space along a stack's main axis. Set `minLength` to preserve a minimum gap.

### SpacerProps


| Property | Type | Required | Description |
| --- | --- | --- | --- |
| `minLength` | `number \| undefined` | No |  |
| `padding` | `number \| EdgeInsets \| undefined` | No |  |
| `background` | `string \| undefined` | No |  |
| `cornerRadius` | `number \| undefined` | No |  |
| `frame` | `Frame \| undefined` | No |  |
| `opacity` | `number \| undefined` | No |  |
| `disabled` | `boolean \| undefined` | No |  |
| `hidden` | `boolean \| undefined` | No |  |
| `color` | `string \| undefined` | No | Foreground color. |
| `help` | `string \| undefined` | No | Tooltip. |
| `tag` | `string \| undefined` | No | Stable row identity for selectable containers (List/Table selection). A selectable List reports and receives selection as its rows' tags. |
| `badge` | `string \| number \| undefined` | No | Badge shown on Tab items and List rows (counts, short strings). |
| `accessibilityLabel` | `string \| undefined` | No | Assistive-tech label (VoiceOver / Narrator). |
| `accessibilityHint` | `string \| undefined` | No | Assistive-tech hint describing the result of activating the element. |
| `accessibilityIdentifier` | `string \| undefined` | No | Stable identifier for UI automation (AX identifier / AutomationId). |
| `key` | `string \| number \| undefined` | No |  |

```tsx
<HStack>
  <Text>Leading</Text>
  <Spacer minLength={16} />
  <Text>Trailing</Text>
</HStack>
```

## Divider [#divider]

Renders the platform divider. It has no component-specific props beyond common props.

### DividerProps


| Property | Type | Required | Description |
| --- | --- | --- | --- |
| `padding` | `number \| EdgeInsets \| undefined` | No |  |
| `background` | `string \| undefined` | No |  |
| `cornerRadius` | `number \| undefined` | No |  |
| `frame` | `Frame \| undefined` | No |  |
| `opacity` | `number \| undefined` | No |  |
| `disabled` | `boolean \| undefined` | No |  |
| `hidden` | `boolean \| undefined` | No |  |
| `color` | `string \| undefined` | No | Foreground color. |
| `help` | `string \| undefined` | No | Tooltip. |
| `tag` | `string \| undefined` | No | Stable row identity for selectable containers (List/Table selection). A selectable List reports and receives selection as its rows' tags. |
| `badge` | `string \| number \| undefined` | No | Badge shown on Tab items and List rows (counts, short strings). |
| `accessibilityLabel` | `string \| undefined` | No | Assistive-tech label (VoiceOver / Narrator). |
| `accessibilityHint` | `string \| undefined` | No | Assistive-tech hint describing the result of activating the element. |
| `accessibilityIdentifier` | `string \| undefined` | No | Stable identifier for UI automation (AX identifier / AutomationId). |
| `key` | `string \| number \| undefined` | No |  |

```tsx
<VStack spacing={8}>
  <Text>Above</Text>
  <Divider />
  <Text>Below</Text>
</VStack>
```

## ScrollView [#scrollview]

Scrolls children on the `vertical` axis by default, or on the `horizontal` axis.

### ScrollViewProps


| Property | Type | Required | Description |
| --- | --- | --- | --- |
| `axis` | `"vertical" \| "horizontal" \| undefined` | No |  |
| `children` | `ReactNode` | No |  |
| `padding` | `number \| EdgeInsets \| undefined` | No |  |
| `background` | `string \| undefined` | No |  |
| `cornerRadius` | `number \| undefined` | No |  |
| `frame` | `Frame \| undefined` | No |  |
| `opacity` | `number \| undefined` | No |  |
| `disabled` | `boolean \| undefined` | No |  |
| `hidden` | `boolean \| undefined` | No |  |
| `color` | `string \| undefined` | No | Foreground color. |
| `help` | `string \| undefined` | No | Tooltip. |
| `tag` | `string \| undefined` | No | Stable row identity for selectable containers (List/Table selection). A selectable List reports and receives selection as its rows' tags. |
| `badge` | `string \| number \| undefined` | No | Badge shown on Tab items and List rows (counts, short strings). |
| `accessibilityLabel` | `string \| undefined` | No | Assistive-tech label (VoiceOver / Narrator). |
| `accessibilityHint` | `string \| undefined` | No | Assistive-tech hint describing the result of activating the element. |
| `accessibilityIdentifier` | `string \| undefined` | No | Stable identifier for UI automation (AX identifier / AutomationId). |
| `key` | `string \| number \| undefined` | No |  |

```tsx
<ScrollView axis="vertical" frame={{ maxHeight: 'infinity' }}>
  <VStack spacing={8}>{rows}</VStack>
</ScrollView>
```

## List [#list]

Renders native list rows and optionally controls selection through child `tag` props.

### ListProps


| Property | Type | Required | Description |
| --- | --- | --- | --- |
| `value` | `string \| string[] \| null \| undefined` | No | Controlled selection: a child row's `tag` (single), an array of tags (multiple), or null for no selection. The presence of this prop (even null) is what makes the list selectable; rows identify themselves via the `tag` common prop. |
| `selectionMode` | `"single" \| "multiple" \| undefined` | No |  |
| `style` | `"automatic" \| "sidebar" \| undefined` | No | 'sidebar' renders the platform source-list material (macOS sidebars). |
| `onChange` | `((value: string \| string[] \| null) => void) \| undefined` | No |  |
| `children` | `ReactNode` | No |  |
| `padding` | `number \| EdgeInsets \| undefined` | No |  |
| `background` | `string \| undefined` | No |  |
| `cornerRadius` | `number \| undefined` | No |  |
| `frame` | `Frame \| undefined` | No |  |
| `opacity` | `number \| undefined` | No |  |
| `disabled` | `boolean \| undefined` | No |  |
| `hidden` | `boolean \| undefined` | No |  |
| `color` | `string \| undefined` | No | Foreground color. |
| `help` | `string \| undefined` | No | Tooltip. |
| `tag` | `string \| undefined` | No | Stable row identity for selectable containers (List/Table selection). A selectable List reports and receives selection as its rows' tags. |
| `badge` | `string \| number \| undefined` | No | Badge shown on Tab items and List rows (counts, short strings). |
| `accessibilityLabel` | `string \| undefined` | No | Assistive-tech label (VoiceOver / Narrator). |
| `accessibilityHint` | `string \| undefined` | No | Assistive-tech hint describing the result of activating the element. |
| `accessibilityIdentifier` | `string \| undefined` | No | Stable identifier for UI automation (AX identifier / AutomationId). |
| `key` | `string \| number \| undefined` | No |  |

```tsx
<List value={selected} onChange={setSelected} selectionMode="single">
  <Text tag="one">First</Text>
  <Text tag="two">Second</Text>
</List>
```

The presence of `value`, including `value={null}`, makes the list selectable. Use `selectionMode="multiple"` with a string array. The `sidebar` style uses platform source-list treatment where available.

Direct rows and rows nested inside `Section` participate in controlled
selection and render their `badge` values on both hosts.

---

# Menus

> Add native dropdown and context menus from serializable item trees.

Canonical: https://natui.dev/docs/components/menus

## Menu [#menu]

Renders a dropdown-menu button. Children form its label and `items` defines the native menu tree.

### MenuProps

A dropdown-menu button; children form the button label.

| Property | Type | Required | Description |
| --- | --- | --- | --- |
| `children` | `ReactNode` | No |  |
| `items` | `MenuItemSpec[]` | Yes |  |
| `systemImage` | `string \| undefined` | No |  |
| `onSelect` | `((id: string) => void) \| undefined` | No |  |
| `padding` | `number \| EdgeInsets \| undefined` | No |  |
| `background` | `string \| undefined` | No |  |
| `cornerRadius` | `number \| undefined` | No |  |
| `frame` | `Frame \| undefined` | No |  |
| `opacity` | `number \| undefined` | No |  |
| `disabled` | `boolean \| undefined` | No |  |
| `hidden` | `boolean \| undefined` | No |  |
| `color` | `string \| undefined` | No | Foreground color. |
| `help` | `string \| undefined` | No | Tooltip. |
| `tag` | `string \| undefined` | No | Stable row identity for selectable containers (List/Table selection). A selectable List reports and receives selection as its rows' tags. |
| `badge` | `string \| number \| undefined` | No | Badge shown on Tab items and List rows (counts, short strings). |
| `accessibilityLabel` | `string \| undefined` | No | Assistive-tech label (VoiceOver / Narrator). |
| `accessibilityHint` | `string \| undefined` | No | Assistive-tech hint describing the result of activating the element. |
| `accessibilityIdentifier` | `string \| undefined` | No | Stable identifier for UI automation (AX identifier / AutomationId). |
| `key` | `string \| number \| undefined` | No |  |

```tsx
<Menu
  systemImage="square.and.arrow.up"
  items={[
    { id: 'png', label: 'PNG' },
    { id: 'csv', label: 'CSV' },
    { divider: true },
    { id: 'delete', label: 'Delete', role: 'destructive' },
  ]}
  onSelect={exportAs}
>
  Export
</Menu>
```

## ContextMenu [#contextmenu]

Wraps its children as a right-click target.

### ContextMenuProps

Wraps its children as the right-click (context menu) target.

| Property | Type | Required | Description |
| --- | --- | --- | --- |
| `items` | `MenuItemSpec[]` | Yes |  |
| `onSelect` | `((id: string) => void) \| undefined` | No |  |
| `children` | `ReactNode` | No |  |
| `padding` | `number \| EdgeInsets \| undefined` | No |  |
| `background` | `string \| undefined` | No |  |
| `cornerRadius` | `number \| undefined` | No |  |
| `frame` | `Frame \| undefined` | No |  |
| `opacity` | `number \| undefined` | No |  |
| `disabled` | `boolean \| undefined` | No |  |
| `hidden` | `boolean \| undefined` | No |  |
| `color` | `string \| undefined` | No | Foreground color. |
| `help` | `string \| undefined` | No | Tooltip. |
| `tag` | `string \| undefined` | No | Stable row identity for selectable containers (List/Table selection). A selectable List reports and receives selection as its rows' tags. |
| `badge` | `string \| number \| undefined` | No | Badge shown on Tab items and List rows (counts, short strings). |
| `accessibilityLabel` | `string \| undefined` | No | Assistive-tech label (VoiceOver / Narrator). |
| `accessibilityHint` | `string \| undefined` | No | Assistive-tech hint describing the result of activating the element. |
| `accessibilityIdentifier` | `string \| undefined` | No | Stable identifier for UI automation (AX identifier / AutomationId). |
| `key` | `string \| number \| undefined` | No |  |

```tsx
<ContextMenu
  items={[
    { id: 'duplicate', label: 'Duplicate' },
    { id: 'delete', label: 'Delete', role: 'destructive' },
  ]}
  onSelect={handleRowAction}
>
  <Text>Selected row</Text>
</ContextMenu>
```

## Item trees [#item-trees]

Action items support `id`, `label`, `systemImage`, `role`, `shortcut`, `disabled`, `checked`, and nested `children`. A divider is `{ divider: true }`.

Selection events fire only for enabled leaf actions. Checkmarks are prop-driven, so update the source data after selection. Command roles do not emit a selection event. Most invoke a platform command, while the Windows `about` role is currently inert.

On Windows, element children inside a `Menu` label are ignored. Use text children or `systemImage`.

---

# Presentation components

> Present controlled native sheets, alerts, and anchored popovers.

Canonical: https://natui.dev/docs/components/presentation

All presentation state is controlled by React. Native dismissal reports `false` through `onChange`.

## Sheet [#sheet]

### SheetProps

A modal sheet. `value` controls presentation; host-side dismissal is an
optimistic change(false), so an app that keeps `value` true gets
prevent-dismissal via the standard corrective update. Children materialize
eagerly; gate expensive content with `{open && <Content/>}`.

| Property | Type | Required | Description |
| --- | --- | --- | --- |
| `value` | `boolean` | Yes |  |
| `onChange` | `((presented: boolean) => void) \| undefined` | No |  |
| `children` | `ReactNode` | No |  |
| `padding` | `number \| EdgeInsets \| undefined` | No |  |
| `background` | `string \| undefined` | No |  |
| `cornerRadius` | `number \| undefined` | No |  |
| `frame` | `Frame \| undefined` | No |  |
| `opacity` | `number \| undefined` | No |  |
| `disabled` | `boolean \| undefined` | No |  |
| `hidden` | `boolean \| undefined` | No |  |
| `color` | `string \| undefined` | No | Foreground color. |
| `help` | `string \| undefined` | No | Tooltip. |
| `tag` | `string \| undefined` | No | Stable row identity for selectable containers (List/Table selection). A selectable List reports and receives selection as its rows' tags. |
| `badge` | `string \| number \| undefined` | No | Badge shown on Tab items and List rows (counts, short strings). |
| `accessibilityLabel` | `string \| undefined` | No | Assistive-tech label (VoiceOver / Narrator). |
| `accessibilityHint` | `string \| undefined` | No | Assistive-tech hint describing the result of activating the element. |
| `accessibilityIdentifier` | `string \| undefined` | No | Stable identifier for UI automation (AX identifier / AutomationId). |
| `key` | `string \| number \| undefined` | No |  |

```tsx
<Sheet value={open} onChange={setOpen}>
  <VStack spacing={12} padding={20}>
    <Text font="headline">New item</Text>
    <Button onPress={() => setOpen(false)}>Done</Button>
  </VStack>
</Sheet>
```

Children materialize even while the sheet is closed. Gate expensive content with `{open && <Content />}` when necessary.

Both hosts use native popup presentation for sheets. Popup content is outside
the host-rendered window screenshot surface.

## Alert [#alert]

Alerts are data-driven rather than child-based:

### AlertProps

A native alert dialog, fully data-driven (no children). Button presses
emit onSelect(buttonId) FIRST, then the dismissal change(false).

| Property | Type | Required | Description |
| --- | --- | --- | --- |
| `value` | `boolean` | Yes |  |
| `title` | `string` | Yes |  |
| `message` | `string \| undefined` | No |  |
| `buttons` | `AlertButtonSpec[]` | Yes |  |
| `onSelect` | `((buttonId: string) => void) \| undefined` | No |  |
| `onChange` | `((presented: boolean) => void) \| undefined` | No |  |
| `padding` | `number \| EdgeInsets \| undefined` | No |  |
| `background` | `string \| undefined` | No |  |
| `cornerRadius` | `number \| undefined` | No |  |
| `frame` | `Frame \| undefined` | No |  |
| `opacity` | `number \| undefined` | No |  |
| `disabled` | `boolean \| undefined` | No |  |
| `hidden` | `boolean \| undefined` | No |  |
| `color` | `string \| undefined` | No | Foreground color. |
| `help` | `string \| undefined` | No | Tooltip. |
| `tag` | `string \| undefined` | No | Stable row identity for selectable containers (List/Table selection). A selectable List reports and receives selection as its rows' tags. |
| `badge` | `string \| number \| undefined` | No | Badge shown on Tab items and List rows (counts, short strings). |
| `accessibilityLabel` | `string \| undefined` | No | Assistive-tech label (VoiceOver / Narrator). |
| `accessibilityHint` | `string \| undefined` | No | Assistive-tech hint describing the result of activating the element. |
| `accessibilityIdentifier` | `string \| undefined` | No | Stable identifier for UI automation (AX identifier / AutomationId). |
| `key` | `string \| number \| undefined` | No |  |

```tsx
<Alert
  value={confirming}
  title="Delete item?"
  message="This cannot be undone."
  buttons={[
    { id: 'cancel', label: 'Cancel', role: 'cancel' },
    { id: 'delete', label: 'Delete', role: 'destructive' },
  ]}
  onSelect={handleAlertButton}
  onChange={setConfirming}
/>
```

Button selection fires before the dismissal change. All button specs are
preserved. A cancel-role button handles the platform cancel action, and
destructive actions receive critical styling.

## Popover and PopoverContent [#popover-and-popovercontent]

Ordinary `Popover` children form the anchor. A single `PopoverContent` child forms the presented body.

### PopoverProps

An anchored popover. Ordinary children render inline as the anchor; the
single PopoverContent child is the presented content.

| Property | Type | Required | Description |
| --- | --- | --- | --- |
| `value` | `boolean` | Yes |  |
| `arrowEdge` | `"top" \| "bottom" \| "leading" \| "trailing" \| undefined` | No |  |
| `onChange` | `((presented: boolean) => void) \| undefined` | No |  |
| `children` | `ReactNode` | No |  |
| `padding` | `number \| EdgeInsets \| undefined` | No |  |
| `background` | `string \| undefined` | No |  |
| `cornerRadius` | `number \| undefined` | No |  |
| `frame` | `Frame \| undefined` | No |  |
| `opacity` | `number \| undefined` | No |  |
| `disabled` | `boolean \| undefined` | No |  |
| `hidden` | `boolean \| undefined` | No |  |
| `color` | `string \| undefined` | No | Foreground color. |
| `help` | `string \| undefined` | No | Tooltip. |
| `tag` | `string \| undefined` | No | Stable row identity for selectable containers (List/Table selection). A selectable List reports and receives selection as its rows' tags. |
| `badge` | `string \| number \| undefined` | No | Badge shown on Tab items and List rows (counts, short strings). |
| `accessibilityLabel` | `string \| undefined` | No | Assistive-tech label (VoiceOver / Narrator). |
| `accessibilityHint` | `string \| undefined` | No | Assistive-tech hint describing the result of activating the element. |
| `accessibilityIdentifier` | `string \| undefined` | No | Stable identifier for UI automation (AX identifier / AutomationId). |
| `key` | `string \| number \| undefined` | No |  |

### PopoverContentProps


| Property | Type | Required | Description |
| --- | --- | --- | --- |
| `children` | `ReactNode` | No |  |
| `padding` | `number \| EdgeInsets \| undefined` | No |  |
| `background` | `string \| undefined` | No |  |
| `cornerRadius` | `number \| undefined` | No |  |
| `frame` | `Frame \| undefined` | No |  |
| `opacity` | `number \| undefined` | No |  |
| `disabled` | `boolean \| undefined` | No |  |
| `hidden` | `boolean \| undefined` | No |  |
| `color` | `string \| undefined` | No | Foreground color. |
| `help` | `string \| undefined` | No | Tooltip. |
| `tag` | `string \| undefined` | No | Stable row identity for selectable containers (List/Table selection). A selectable List reports and receives selection as its rows' tags. |
| `badge` | `string \| number \| undefined` | No | Badge shown on Tab items and List rows (counts, short strings). |
| `accessibilityLabel` | `string \| undefined` | No | Assistive-tech label (VoiceOver / Narrator). |
| `accessibilityHint` | `string \| undefined` | No | Assistive-tech hint describing the result of activating the element. |
| `accessibilityIdentifier` | `string \| undefined` | No | Stable identifier for UI automation (AX identifier / AutomationId). |
| `key` | `string \| number \| undefined` | No |  |

```tsx
<Popover value={open} arrowEdge="bottom" onChange={setOpen}>
  <Button onPress={() => setOpen(true)}>Help</Button>
  <PopoverContent padding={12}>
    <Text>This is native UI.</Text>
  </PopoverContent>
</Popover>
```

Open sheets, alerts, popovers, and menus use popup layers on Windows and are
not included in `RenderTargetBitmap` screenshots.

---

# Architecture

> Understand the NatUI reconciler, bridge, native hosts, controlled state, and runtime paths.

Canonical: https://natui.dev/docs/internals/architecture

```text
┌────────────────────────── JavaScript process ──────────────────────┐
│ React application                                                  │
│       ↓                                                            │
│ react-reconciler 0.33 with a JavaScript shadow tree                │
│       ↓ atomic NDJSON commit                 ↑ native events       │
│ transport and Bridge                                               │
└───────┼──────────────────────────────────────┼──────────────────────┘
        ↓                                      │
┌────────────────────────── native host ───────┴─────────────────────┐
│ macOS: Swift and SwiftUI        │ Windows: C# and WinUI 3          │
│ observable node store           │ node registry and control map    │
│ recursive native view mapping   │ native controls and Grid layout  │
└─────────────────────────────────┴──────────────────────────────────┘
```

## Native layout owns geometry [#native-layout-owns-geometry]

NatUI maps the React tree to platform declarative primitives. `VStack` becomes a SwiftUI `VStack` on macOS and a vertical native grid stack on Windows. The native toolkit owns layout proposals, focus, accessibility, theming, and control behavior.

There is no Yoga or browser layout layer. The tradeoff is intentional: applications get platform-native behavior rather than pixel-identical cross-platform rendering or CSS-style layout.

## React reconciler [#react-reconciler]

`packages/natui` uses react-reconciler mutation mode with a JavaScript shadow tree. Each instance records its id, kind, props, handlers, children, and materialization state.

Render-phase methods only construct or rearrange the shadow tree. Protocol operations are emitted during commit work after a node attaches to a materialized parent.

All operations from one React commit are buffered and sent as one `commit` message. A host applies the complete batch on its UI thread before one render pass, so it never displays an intermediate commit state.

React may discard render-phase instances. Deferring protocol creation until attachment prevents abandoned nodes from leaking into the native tree.

## Props and handlers [#props-and-handlers]

Event-handler functions remain in a JavaScript registry. The host emits an event with the node id and event name, then the bridge locates and invokes the current handler.

Other props are validated and deep-copied into documented JSON values before serialization. Invalid nested values are reported with their component kind and path. A commit is all-or-nothing, so serialization failure cannot partially mutate the native tree.

## Controlled inputs [#controlled-inputs]

Native controls apply edits optimistically for immediate feedback. Each edit carries a per-node sequence number. JavaScript acknowledges the highest processed sequence on its next update.

An acknowledgement older than the host's current sequence cannot overwrite the latest local value. When the acknowledgement catches up, React becomes authoritative again, including for transformations and rejected edits.

Events run at React's discrete priority and flush synchronously. After each controlled change, the bridge checks whether React adopted the value. If not, it sends a corrective update carrying the event acknowledgement.

See [controlled state](/docs/guides/controlled-state) and the [wire protocol](/docs/internals/protocol).

## Native hosts [#native-hosts]

### macOS [#macos]

The Swift host stores each node in an observable model. A recursive SwiftUI view switches on the node kind without type erasure, and children use stable ids so React moves remain native moves.

The development host is a Swift Package Manager executable with native GUI
application identity. It supports the Node standard-stream mode and an
embedded JavaScriptCore mode. The reference packager wraps the release host,
application JavaScript, compatibility manifest, and native metadata in a
standard `.app`.

### Windows [#windows]

The Windows development host is an unpackaged, self-contained WinUI 3
executable. It uses a node registry and native control map. Grid-based stacks
provide the flexible tracks needed by `Spacer` and infinite frames.

WinUI also raises events for programmatic changes, so prop application uses guards and structural equality checks to prevent feedback loops.

The base component set has real-window Node-mode verification. The host also
embeds V8 for single-process browser bundles through `natui/inproc`.

The reference packager publishes one portable, architecture-specific,
self-contained EXE containing the application JavaScript and manifest as
managed resources. The .NET single-file runtime extracts its runtime
dependencies to a per-user temporary cache at launch.

## Debug surface [#debug-surface]

The protocol includes four verification messages:

* `dump` returns the host's actual native node tree.
* `emit` synthesizes an interaction event.
* `edit` performs a real optimistic controlled edit.
* `screenshot` renders the native window to a PNG and always receives success or error.

These messages allow end-to-end assertions without general-purpose UI automation. Popup layers and some focus or accessibility behavior still need dedicated native testing.

## Runtime and packaging paths [#runtime-and-packaging-paths]

NatUI currently has three launch paths:

* **Node development:** React runs in Node, spawns the native host, and
  exchanges NDJSON over standard streams. This path supports the current
  edit-and-remount development loop.
* **Raw embedded development:** Both hosts evaluate an esbuild browser bundle
  in-process, using system JavaScriptCore on macOS and V8 on Windows. The
  bundle and host exchange protocol messages through `__natui_send` and
  `__natui_recv`. Standard input remains available as a verification debug
  channel.
* **Packaged embedded application:** `pnpm package:demo` builds the same
  embedded runtime into a macOS `.app` or one Windows self-contained EXE. A
  generated manifest records identity, platform, architecture, protocol,
  minimum host API, and the SHA-256 digest of `main.js`.

The native package loader validates the manifest before JavaScript evaluation.
The embedded ready handshake repeats protocol and host API validation at the
runtime boundary.

`runEmbedded` owns the JavaScript lifecycle. Its controller can update the
root and exposes an idempotent `quit()` method. Shutdown synchronously unmounts
React, runs effect cleanup, sends one host quit request, rejects pending bridge
work, and removes the receive hook. Native window close uses the same path.

## Current alpha boundaries [#current-alpha-boundaries]

The repository includes 37 host components, including menus, toolbars, navigation, data views, and presentation. Menus are not out of scope.

Features still outside the current alpha scope include:

* State-preserving React refresh
* A public animation or gesture API
* Multi-window application APIs
* Code signing, macOS notarization, installers, and automatic updates
* Single-instance application orchestration
* A public package-registry CLI or `natui doctor` command
  Accessibility labels, hints, identifiers, and the native controls' default accessibility behavior are in scope.

---

# Wire protocol

> Specify NatUI protocol version 1 messages, operations, events, selection, and sequence acknowledgements.

Canonical: https://natui.dev/docs/internals/protocol

The Node renderer and native host communicate with one UTF-8 JSON object per line. The process transport uses the host's standard input and output. Diagnostics go to standard error, and a host must not write non-protocol text to standard output.

Receivers ignore unknown message types for forward compatibility.

## Handshake [#handshake]

1. The host sends `{"t":"ready","platform":"macos","protocol":1,"hostApi":1}`.
2. JavaScript checks that the protocol is 1, the host API is at least 1, and the platform is known. Node mode also checks that the platform matches the current operating system.
3. JavaScript sends a `window` message, then begins committing the React tree.

A mismatch is a startup failure. JavaScript terminates the incompatible or
half-started host. Embedded startup also removes its host-to-JavaScript receive
hook.

The protocol version describes wire-format compatibility. The host API is a
monotonic capability level for additive components and native behavior that
keep the same wire format. A renderer accepts a host API equal to or newer
than its required level.

Packaged applications add a bundle manifest check before this handshake. The
native loader validates bundle schema, exact protocol, minimum host API,
platform, architecture, and the SHA-256 digest of the JavaScript entry before
evaluating it.

## JavaScript to host messages [#javascript-to-host-messages]

| Message      | Shape                                                      | Meaning                               |
| ------------ | ---------------------------------------------------------- | ------------------------------------- |
| `window`     | `{"t":"window","props":{...}}`                             | Configure and show the main window    |
| `commit`     | `{"t":"commit","ops":[...]}`                               | Apply one atomic React commit         |
| `dump`       | `{"t":"dump"}`                                             | Request the native node tree          |
| `screenshot` | `{"t":"screenshot","path":string}`                         | Render the window to a PNG            |
| `emit`       | `{"t":"emit","id":number,"name":string,"payload"?:object}` | Synthesize an event                   |
| `edit`       | `{"t":"edit","id":number,"value":any}`                     | Perform an optimistic controlled edit |
| `quit`       | `{"t":"quit"}`                                             | Exit cleanly                          |

Debug messages can be removed from a production host.

## Commit operations [#commit-operations]

Node ids are positive integers. Id `0` is the root container.

| Operation    | Meaning                                            |
| ------------ | -------------------------------------------------- |
| `create`     | Create a detached typed node with serialized props |
| `createText` | Create a detached raw text node                    |
| `append`     | Append or move a child to the end of a parent      |
| `insert`     | Insert or move a child before a sibling            |
| `remove`     | Destroy a child and its subtree                    |
| `update`     | Replace all props, optionally carrying `ack`       |
| `text`       | Replace raw text content                           |
| `clear`      | Destroy every root child                           |

The host applies every operation in a commit before updating visible UI.

## Host to JavaScript messages [#host-to-javascript-messages]

| Message  | Meaning                                               |
| -------- | ----------------------------------------------------- |
| `ready`  | Report platform, protocol version, and host API level |
| `event`  | Report an interaction on a node                       |
| `window` | Report native window close                            |
| `tree`   | Reply to `dump`                                       |
| `shot`   | Reply to `screenshot`, with optional `error`          |

The host always replies to `screenshot`. On failure it includes `error` and does not produce a usable file.

## Events [#events]

| Component                        | Event              | Payload value                 |
| -------------------------------- | ------------------ | ----------------------------- |
| `Button`, `Link`                 | `press`            | none                          |
| `TextField`, `SearchField`       | `change`, `submit` | string                        |
| `Toggle`                         | `change`           | boolean                       |
| `Slider`, `Stepper`              | `change`           | number                        |
| `Picker`, `TabView`              | `change`           | string                        |
| `DatePicker`                     | `change`           | local ISO string              |
| `TextEditor`                     | `change`           | string                        |
| `Sheet`, `Alert`, `Popover`      | `change`           | boolean                       |
| `Alert`                          | `select`           | button id                     |
| `SplitView`                      | `change`           | `all` or `detailOnly`         |
| `DisclosureGroup`                | `change`           | boolean                       |
| `List`, `Table`                  | `change`           | string, string array, or null |
| `Table`                          | `sortChange`       | `{ key, order }`              |
| `MenuBar`, `Menu`, `ContextMenu` | `select`           | item id                       |
| `Toolbar`                        | `action`           | item id                       |
| `Toolbar`                        | `search`           | text                          |

Only `change` events carry `seq`. Press, submit, select, action, search, and sort requests are fire-and-forget.

## Sequence acknowledgements [#sequence-acknowledgements]

On every optimistic controlled edit:

1. The host increments a per-node counter and sends it as `seq`.
2. JavaScript records the highest sequence processed for that node.
3. An update generated after that event carries the sequence as `ack`.
4. If the host has a newer sequence, it keeps its local `value` while applying other props.
5. When `ack` equals the local counter, the full update is authoritative.

An update without `ack` is fully authoritative.

After the synchronous handler flush, JavaScript compares the committed value with the event value. If they differ, it synthesizes a corrective update with the event acknowledgement. This covers handlers that reject or clamp input and controls without handlers.

An asynchronously adopted value is corrected first, then applied by the later React commit.

## Controlled kinds [#controlled-kinds]

Each controlled kind has exactly one controlled prop named `value`.

| Kind                                     | Value                                                           |
| ---------------------------------------- | --------------------------------------------------------------- |
| `TextField`, `SearchField`, `TextEditor` | string                                                          |
| `Toggle`                                 | boolean                                                         |
| `Slider`, `Stepper`                      | number                                                          |
| `Picker`, `TabView`                      | string                                                          |
| `DatePicker`                             | local ISO string                                                |
| `Sheet`, `Alert`, `Popover`              | boolean                                                         |
| `SplitView`                              | `all` or `detailOnly`; native visibility changes are optimistic |
| `List`, `Table`                          | string, string array, or null                                   |
| `DisclosureGroup`                        | boolean                                                         |

Presentation hosts can optimistically set only `false`, representing native dismissal. Keeping `value` true prevents dismissal through the same corrective mechanism.

## Presentation ordering [#presentation-ordering]

Sheet and popover content materializes eagerly whether or not it is presented.

Alert children are ignored because its content is data-driven. A button press emits `select` first and dismissal `change(false)` second. The ordering lets the select handler close state without re-presenting the alert between events.

A popover's ordinary children form its anchor. Its first `PopoverContent` child forms the presented body; extra content slots are ignored with a diagnostic.

## Menu and toolbar specifications [#menu-and-toolbar-specifications]

Menu items are recursive JSON data:

```text
MenuItemSpec =
  { id, label, systemImage?, role?, shortcut?, disabled?, checked?, children? }
  | { divider: true }
```

Selection fires only for enabled leaves. `checked` is prop-driven. Command roles do not emit selection, except `destructive`, which is a style and still emits. Command roles invoke platform actions where supported; the Windows `about` role is currently inert.

Shortcuts use tokens such as `cmd`, `shift`, `alt`, and `ctrl` plus a key.

Toolbar items can be spacers, flexible spaces, buttons, toggles, menus, or search fields. Buttons and toggles emit `action`. Toolbar menu leaves also emit `action`. Search text emits `search` and is not echoed into the item spec.

## Selection and sorting [#selection-and-sorting]

A `List` becomes selectable when its props include `value`, including null. Rows use the common `tag` prop as identity.

Single selection is a string or null. Multiple selection is a sorted string array, and an empty selection is `[]`, not null. Rows without tags should not be used in selectable lists.

Table selection uses row ids and the same value shapes.

Sorting is request-based. The host emits `sortChange` without a sequence number and never reorders rows. The application sorts its data and returns both reordered rows and the new descriptor.

## Root-attached chrome [#root-attached-chrome]

`MenuBar` and `Toolbar` remain protocol nodes and appear in tree dumps, but they do not render in normal content. For portable behavior, provide one direct root child of each kind. macOS hoists the first direct root child. Windows creates hosted chrome for every such node when it is created, even if it is nested, so duplicate or nested chrome is intentionally unsupported application structure.

Structurally equal props do not rebuild chrome, which prevents unrelated React commits from tearing down an open menu.

## Node props [#node-props]

All dimensions are logical points. Colors are `#RRGGBB` or `#RRGGBBAA`.

Common props cover padding, background, corner radius, frame, opacity, disabled and hidden state, foreground color, tooltips, selection tags, badges, and accessibility fields.

Component-specific props and platform mappings are documented in the [component catalog](/docs/components). Every wire prop must be JSON-compatible. Event handlers remain in JavaScript and never cross the wire.

---

# First app

> Render React state into a real native NatUI window.

Canonical: https://natui.dev/docs/start/first-app

Create a React component using NatUI host components:

```tsx typecheck
import { useState } from 'react';
import { Button, Text, TextField, VStack, run } from 'natui';

function App() {
  const [name, setName] = useState('');

  return (
    <VStack spacing={12} padding={20} alignment="leading">
      <Text font="title" weight="semibold">Welcome</Text>
      <TextField
        value={name}
        placeholder="Your name"
        onChange={setName}
        frame={{ width: 260 }}
      />
      <Button variant="prominent" disabled={!name}>
        {name ? `Continue as ${name}` : 'Continue'}
      </Button>
    </VStack>
  );
}

await run(<App />, {
  title: 'First NatUI app',
  width: 420,
  height: 260,
});
```

`run` starts the platform host, validates its handshake, configures the window, and resolves after React's first commit has been flushed to the host transport. Protocol version 1 has no host acknowledgement for a completed native commit. Use `dump()` in verification code when you need to observe the host tree.

All sizing uses logical points. Native layout decides the final geometry, so expect intentional visual differences between SwiftUI and WinUI 3.

## Keep inputs controlled [#keep-inputs-controlled]

Interactive values are ordinary React state. Provide both `value` and `onChange` when the user should be able to edit a control. NatUI uses sequence acknowledgements to prevent a slower JavaScript round trip from overwriting newer native input.

Continue with [controlled state](/docs/guides/controlled-state) for the complete model.

---

# Getting started

> Set up NatUI from source and open your first native desktop window.

Canonical: https://natui.dev/docs/start

NatUI is currently used directly from its repository. Clone the source, install the pnpm workspace, build the native host for your platform, then run one of the included examples.

1. Complete [source setup](/docs/start/source-setup).
2. Build the [macOS](/docs/start/macos) or [Windows](/docs/start/windows) host.
3. Read the [first app](/docs/start/first-app) walkthrough.
4. Explore the [kitchen sink](/docs/start/kitchen-sink) for a working app-shell and multi-component example.

The JavaScript runtime validates the protocol version and platform reported by the host during startup. Build both sides from the same checkout for the simplest known-compatible setup, although any host and renderer that both implement protocol version 1 can interoperate.

---

# Kitchen sink

> Explore NatUI app-shell, form, data, menu, and presentation workflows in one native example.

Canonical: https://natui.dev/docs/start/kitchen-sink

`examples/kitchen-sink` is a project and task manager built to exercise app-shell and multi-component workflows. It includes application menus, a toolbar, split navigation, tabs, controlled forms, tables, context menus, sheets, alerts, and popovers. It is not the exhaustive 37-component catalog. Use the [component index](/docs/components) for the complete public surface.

```bash
pnpm build:host:macos
pnpm --filter natui build
pnpm --filter natui-kitchen-sink dev
```

Run its automated real-window verification on macOS or Windows with:

```bash
pnpm verify:kitchen
```

The suite drives the platform's real native window and writes screenshots
under `screenshots/kitchen-sink/`.

Use this example as a behavior reference, especially for:

* Controlled forms and native sequence acknowledgements
* App-shell components that are hoisted into native window chrome
* Client-side table sorting and selection
* Controlled presentation state for sheets, alerts, and popovers

The same assertions run against the SwiftUI and WinUI 3 hosts.

---

# macOS

> Build and verify the native SwiftUI host on macOS.

Canonical: https://natui.dev/docs/start/macos

## Requirements [#requirements]

* macOS 14 or newer
* Xcode command line tools with a Swift 6 toolchain
* Node.js 22 or newer
* pnpm 11

From the repository root:

```bash
pnpm install
pnpm build:host:macos
pnpm demo
```

The host is a Swift Package Manager executable that opens a real `NSWindow` and renders SwiftUI views.

## Verification [#verification]

```bash
pnpm verify
pnpm verify:kitchen
pnpm verify:embedded
pnpm verify:package
```

These local suites require a real window session. They use native tree dumps, synthesized events, optimistic edits, and host-rendered PNG files. They do not rely on browser automation.

* `pnpm verify` covers the base demo and controlled-input stress cases.
* `pnpm verify:kitchen` exercises app-shell and multi-component workflows through the kitchen-sink app.
* `pnpm verify:embedded` runs the demo inside the host with JavaScriptCore and no Node process at runtime.
* `pnpm verify:package` builds and launches the native `.app`, validates its
  handshake and tree, then exercises the normal close lifecycle.

The headless macOS CI job builds the Swift host and `.app`, then validates the
bundle layout, metadata, architecture, entry integrity, and license without
launching it. It does not run the GUI suites.

## Package a macOS application [#package-a-macos-application]

From the repository root:

```bash
pnpm package:demo
```

The command reads `examples/demo/natui.app.json` and writes:

```text
examples/demo/dist/package/NatUIDemo.app
```

The `.app` contains the native executable, generated `Info.plist`, bundled
JavaScript, and a generated manifest with its SHA-256 digest. The loader
validates bundle schema, protocol, minimum host API, architecture, and entry
integrity before JavaScriptCore evaluates the application.

macOS packaging targets the architecture of the machine performing the build.
Build each architecture natively and copy the complete `.app` directory when
moving the application.

The reference packager does not perform code signing or notarization. It also
does not create an installer, automatic updater, single-instance coordinator,
or multi-window application. See
[application bundles](/docs/guides/application-bundles).

---

# Source setup

> Clone the NatUI repository and install its pnpm workspace prerequisites.

Canonical: https://natui.dev/docs/start/source-setup

## Prerequisites [#prerequisites]

* Node.js 22 or newer
* pnpm 11
* Git
* The platform tools described in the macOS or Windows guide

```bash
git clone https://github.com/floklein/natui.git
cd natui
corepack enable
pnpm install
pnpm build
pnpm typecheck
```

`pnpm build` emits the `natui` package into `packages/natui/dist`. The examples resolve the package through the pnpm workspace, so build the package before running a standalone typecheck.

## Package the demo [#package-the-demo]

The repository includes a native application packaging workflow:

```bash
pnpm package:demo
pnpm verify:package
```

It reads `examples/demo/natui.app.json` and produces a native artifact for the
current platform and architecture. macOS requires the Swift toolchain. Windows
requires the .NET SDK and emits one self-contained EXE that extracts runtime
dependencies to a per-user temporary cache when launched.

`pnpm verify:package` opens the packaged application, validates its handshake
and native tree, then exercises the normal close lifecycle. A real desktop
window session is required.

See [application bundles](/docs/guides/application-bundles) for configuration
and distribution boundaries.

## Package entrypoints [#package-entrypoints]

The workspace exposes three entrypoints:

* `natui` for components, `run`, and advanced protocol exports
* `natui/components` for component-only bundles that avoid Node built-ins
* `natui/inproc` for the embedded host entrypoint

NatUI is not documented as a public registry package. The application
packager is currently a repository-local reference workflow, so installation
and examples remain tied to a source checkout.

---

# Windows

> Build and run the native WinUI 3 host on Windows.

Canonical: https://natui.dev/docs/start/windows

## Requirements [#requirements]

* Windows 10 version 1809 or newer
* Windows 11 recommended for the Segoe Fluent Icons font
* .NET 8 SDK or newer
* Node.js 22 or newer
* pnpm 11

The project targets `net8.0-windows` and Windows App SDK 1.8. CI uses the
.NET 8 SDK.

```powershell
pnpm install
dotnet build hosts/windows/NatuiHost -c Release -p:Platform=x64
pnpm demo
```

The host is an unpackaged, self-contained WinUI 3 executable. The JavaScript bridge locates normal debug and release output paths automatically. Set `NATUI_HOST` when your executable is elsewhere:

```powershell
$env:NATUI_HOST = "C:\path\to\NatuiHost.exe"
pnpm demo
```

Do not use `dotnet run` as the spawn target. Its wrapper process breaks the parent-child lifetime and standard-stream semantics expected by NatUI.

## Verification status [#verification-status]

The base demo and its Node-mode end-to-end suite have passed against a real WinUI 3 window, including tree dumps, interaction events, controlled edits, and screenshots.

The Windows host also supports in-process V8 execution:

```powershell
pnpm build
pnpm --filter natui-demo build:embedded
hosts\windows\NatuiHost\bin\x64\Release\net8.0-windows10.0.19041.0\win-x64\NatuiHost.exe --bundle examples\demo\dist\embedded.js
```

Run `pnpm verify:embedded` to exercise the embedded tree, interactions,
sequence acknowledgements, screenshot path, and closed-input lifecycle.

## Package a Windows application [#package-a-windows-application]

From the repository root:

```powershell
pnpm package:demo
```

The command reads `examples/demo/natui.app.json` and writes one portable,
architecture-specific, self-contained EXE:

```text
examples\demo\dist\package\NatUIDemo-0.1.0-windows-x64.exe
```

An ARM64 build uses the `windows-arm64.exe` suffix. The one EXE contains the
application JavaScript, generated manifest, WinUI host, .NET runtime, Windows
App SDK runtime, and V8 dependencies. It does not need Node or a machine-wide
.NET installation at runtime.

At launch, the .NET single-file host extracts runtime dependencies to a cache
under the current user's temporary directory. The cache is runtime-managed and
is not a machine-wide installation.

Run the packaged lifecycle verification in a real desktop session:

```powershell
pnpm verify:package
```

The check launches the EXE from an unrelated working directory, validates the
protocol and host API handshake, waits for the native tree, requests a normal
window close, and requires exit code 0.

Headless Windows CI also builds the EXE and inspects its PE header and .NET
bundle table. It requires exactly one output file and checks that the embedded
runtime includes WinUI, V8, ICU, `resources.pri`, and the application payload.

The reference packager does not sign the EXE or create an installer,
automatic updater, single-instance coordinator, or multi-window application.
See [application bundles](/docs/guides/application-bundles).

See [platform support](/docs/status/platform-support) for component-level differences.

---

# Platform support

> Compare implemented and verified NatUI behavior on macOS and Windows.

Canonical: https://natui.dev/docs/status/platform-support

NatUI is still in Alpha. Support claims distinguish implementation, compilation, and real-window verification.

| Capability                        | macOS                   | Windows                |
| --------------------------------- | ----------------------- | ---------------------- |
| Native toolkit                    | SwiftUI                 | WinUI 3                |
| Base demo workflow                | Real-window verified    | Real-window verified   |
| Kitchen-sink app-shell workflow   | Real-window verified    | Real-window verified   |
| Node process mode                 | Verified                | Verified               |
| Embedded mode                     | JavaScriptCore verified | V8 verified            |
| Native application package        | `.app`                  | One self-contained EXE |
| Host build in CI                  | Yes                     | Yes                    |
| Headless package inspection in CI | Yes                     | Yes                    |
| GUI suites in CI                  | No                      | No                     |

## Cross-platform component support [#cross-platform-component-support]

The Windows differences previously listed on this page are implemented. Both
hosts cover all 37 public components, including their controlled-state,
selection, presentation, and event paths. Individual component pages still
describe platform-native conventions where the operating systems differ.

## Implementation details [#implementation-details]

* Table uses a list-based fallback on macOS 14.0 through 14.3.
* Embedded execution uses system JavaScriptCore on macOS and V8 on Windows.
* Packaged applications validate their generated manifest, protocol, minimum
  host API, architecture, and SHA-256 entry digest before evaluation.
* The Windows single-file EXE extracts runtime dependencies to a per-user
  temporary cache at launch.
* GUI verification runs locally because the hosted CI jobs do not provide a
  normal desktop window session.

These are current implementation details, not promises of permanent behavior.

---

# Roadmap

> Understand the current NatUI boundaries and likely next engineering stages.

Canonical: https://natui.dev/docs/status/roadmap

NatUI currently proves that React can drive a compact, native SwiftUI and WinUI 3 tree while keeping native layout and controlled interaction semantics.

## Current [#current]

* React 19 custom renderer
* 37 typed host components
* SwiftUI and WinUI 3 hosts
* Node development mode
* macOS embedded JavaScriptCore mode
* Windows embedded V8 mode
* Native `.app` and self-contained EXE packaging
* Generated manifest, SHA-256 integrity, protocol, and host API gates
* Idempotent embedded update and shutdown lifecycle
* Protocol-level controlled-input sequence acknowledgements
* Contract tests and native-window verification tools

## Likely next stages [#likely-next-stages]

* Add state-preserving React refresh
* Extend accessibility coverage and native UI automation
* Define stable packaging, versioning, and compatibility policy

## Not currently promised [#not-currently-promised]

* Public package-registry availability
* Multi-window APIs
* Animation or gesture APIs
* Pixel-identical rendering across platforms
* Code signing or macOS notarization
* Installer generation or automatic updates
* Single-instance application orchestration

Roadmap items are directions rather than committed release dates.

---

# Verification status

> See which NatUI behaviors are covered by tests, native tree assertions, and screenshots.

Canonical: https://natui.dev/docs/status/verification

## JavaScript suite [#javascript-suite]

The contract and unit tests cover:

* Reconciler creation, movement, removal, and commit batching
* Prop validation and all-or-nothing serialization
* Host handshake, process exit, and request timeouts
* Protocol and additive host API compatibility
* Embedded controller updates and idempotent React cleanup
* Controlled-value sequence acknowledgements and enforcement
* Menu, toolbar, presentation, selection, and sorting semantics
* Screenshot success, failure, and timeout behavior
* Application configuration, generated manifest, integrity metadata, and native identity

Linux CI runs the JavaScript tests, package build, and typecheck.

## macOS [#macos]

The macOS CI job compiles the Swift host, runs the JavaScript suite, builds the
`.app`, and validates its layout, metadata, Mach-O architecture, entry
integrity, and license. GUI verification is local because hosted CI has no
normal window session.

Local real-window suites cover:

* Base demo in Node mode
* Kitchen-sink app-shell and multi-component workflows
* Embedded JavaScriptCore demo
* Packaged `.app` lifecycle

They assert native tree dumps, interaction events, optimistic edits, sequence acknowledgements, and host-rendered PNG files.

## Windows [#windows]

The blocking Windows CI job compiles the Release x64 WinUI host with .NET 8,
builds the portable EXE, and statically inspects its PE and .NET bundle
contents. The output directory must contain only that EXE.

Local real-window suites cover:

* Base demo in Node mode
* Kitchen-sink app-shell and multi-component workflows
* Embedded V8 demo
* Packaged self-contained EXE lifecycle

They cover the same tree, interaction, controlled-state, sequence
acknowledgement, and screenshot evidence categories as the macOS suites.

## Packaged application verification [#packaged-application-verification]

```bash
pnpm verify:package
```

The command packages the demo for the current platform and architecture, then
launches it from an unrelated working directory. It asserts protocol 1, host
API 1 or newer, materialization of the demo tree, the native close path, and
exit code 0.

Before evaluating JavaScript, each packaged host validates its generated
manifest and SHA-256 entry digest. The manifest also gates bundle schema,
protocol, minimum host API, platform, and architecture.

## Evidence limits [#evidence-limits]

* Tree dumps prove host node state, not every visual detail.
* PNG validation proves captured window content, not popup layers outside the captured surface.
* Debug events prove protocol handling, not physical pointer or keyboard routing.
* Current checks do not constitute a complete accessibility audit.
* The real-window suites do not visit every public component. The component catalog is validated separately against all 37 public exports.
* Package verification does not prove code signing, notarization, installer behavior, automatic updates, single-instance behavior, or multi-window behavior.