2026-05-24 18:14:06 +08:00
# vue-tui
2026-05-24 22:52:09 +08:00
> **Early stage** — under active development. Bug reports welcome, but not recommended for production use yet.
2026-05-27 15:03:18 +08:00
The Vue framework for terminal UIs.
Build with components, develop with HMR, test with confidence.
2026-05-24 18:14:06 +08:00
2026-05-27 15:03:18 +08:00
<p align="center">
<a href="https://npmx.dev/@vue -tui/runtime"><code>@vue -tui/runtime</code></a> · <a href="https://npmx.dev/@vue -tui/cli"><code>@vue -tui/cli</code></a> · <a href="https://npmx.dev/@vue -tui/testing"><code>@vue -tui/testing</code></a>
</p>
- **Vue SFC & JSX** — write terminal interfaces with `<template>` , TSX, or both
2026-05-24 22:07:37 +08:00
- **Flexbox layout** — powered by Yoga, the same engine behind React Native
2026-05-31 21:42:52 +08:00
- **Dev toolkit** _(experimental)_ — **HMR** in the terminal, plus build and preview out of the box
2026-05-27 15:03:18 +08:00
- **Input & focus** — keyboard handling, focus management, Tab navigation, Kitty keyboard protocol
- **Testing harness** — out-of-the-box component-level terminal testing — render, simulate input, assert frames
2026-05-24 18:14:06 +08:00
2026-05-27 15:03:18 +08:00
<p align="center">
<a href="./examples/flappy-bird"><em>Flappy Bird</em></a> — one of the <a href="#examples ">examples</a> included in the repo
<br /><br />
<a href="./examples/flappy-bird">
<img src=".github/assets/flappy-bird-demo.gif" alt="Flappy Bird built with vue-tui" width="690" />
</a>
</p>
2026-05-24 22:15:12 +08:00
2026-05-27 15:03:18 +08:00
## Quick Start
2026-05-24 22:15:12 +08:00
2026-05-27 15:03:18 +08:00
```bash
npx tiged vuejs-ai/vue-tui-starter my-app
cd my-app
npm install
npm run dev
```
2026-06-05 08:28:59 +08:00
Edit `app.vue` and watch the terminal update instantly.
2026-05-27 15:03:18 +08:00
## Example
2026-05-24 18:14:06 +08:00
2026-05-24 22:15:12 +08:00
```ts
// src/main.ts
import { createApp } from "@vue-tui/runtime" ;
2026-06-05 08:28:59 +08:00
import App from "./app.vue" ;
2026-05-24 22:15:12 +08:00
createApp ( App ). mount ();
```
2026-05-24 22:07:37 +08:00
```vue
2026-06-05 08:28:59 +08:00
<!-- src / app . vue -->
2026-05-24 22:33:58 +08:00
< script setup lang = "ts" >
import { shallowRef } from "vue" ;
2026-05-24 22:07:37 +08:00
import { Box , Text , useInput } from "@vue-tui/runtime" ;
2026-05-24 22:33:58 +08:00
const count = shallowRef ( 0 );
2026-05-24 22:07:37 +08:00
2026-05-24 22:33:58 +08:00
useInput (( input ) => {
if ( input === "+" ) count . value ++ ;
if ( input === "-" ) count . value -- ;
2026-05-24 22:07:37 +08:00
});
</ script >
< template >
< Box >
< Text > Count : </ Text >
< Text bold color = "green" >{{ count }}</ Text >
< Text dimColor > ( + /- to change)</Text>
</ Box >
</ template >
```
2026-05-27 15:03:18 +08:00
## Table of Contents
- [Quick Start ](#quick-start )
- [Example ](#example )
- [Packages ](#packages )
- [Examples ](#examples )
- [Components ](#components )
- [Composables (Hooks) ](#composables-hooks )
- [Testing ](#testing )
- [Development ](#development )
2026-05-27 15:13:59 +08:00
- [Contributing ](#contributing )
2026-05-27 15:03:18 +08:00
- [Credits ](#credits )
- [License ](#license )
## Packages
2026-05-30 23:32:22 +08:00
| Package | Description |
| -------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| [`@vue-tui/runtime` ](https://www.npmjs.com/package/@vue-tui/runtime ) | The core framework — Vue 3 renderer for the terminal with components (`Box` , `Text` , `Static` , etc.), composables (`useInput` , `useFocus` , `useApp` , etc.), and yoga-based flexbox layout |
| [`@vue-tui/cli` ](https://www.npmjs.com/package/@vue-tui/cli ) | Development tool — `vue-tui dev` starts your app with Vite-powered HMR |
| [`@vue-tui/testing` ](https://www.npmjs.com/package/@vue-tui/testing ) | Test harness — render in an isolated fake terminal, simulate input, assert output frame by frame |
2026-05-27 15:03:18 +08:00
2026-05-24 23:35:25 +08:00
## Examples
| Example | Description |
| --------------------------------------------- | ----------------------------------------------------------- |
| [`basic-template` ](./examples/basic-template ) | Vue SFC with `<template>` syntax |
| [`basic-jsx` ](./examples/basic-jsx ) | Same app in TSX |
| [`coding-agent` ](./examples/coding-agent ) | AI coding agent with LLM streaming and interactive UI |
| [`flappy-bird` ](./examples/flappy-bird ) | Physics-based terminal game with reactive state and borders |
2026-05-24 22:07:37 +08:00
## Components
| Component | Description |
| ----------------------------------- | ---------------------------------------------------------------------------------------------- |
| [`<Box>` ](./packages/runtime ) | Flexbox container — direction, wrap, align, justify, gap, padding, margin, borders, background |
| [`<Text>` ](./packages/runtime ) | Styled text — color, bold, italic, underline, strikethrough, dimColor, wrap/truncate modes |
| [`<Spacer>` ](./packages/runtime ) | Expands to fill available space (`flex-grow: 1` ) |
| [`<Newline>` ](./packages/runtime ) | Inserts line breaks (configurable `count` ) |
| [`<Static>` ](./packages/runtime ) | Renders a list of items once, above the redrawn region |
| [`<Transform>` ](./packages/runtime ) | Applies a string transform function to each rendered line |
2026-05-27 15:03:18 +08:00
## Composables (Hooks)
2026-05-24 22:07:37 +08:00
2026-05-27 15:03:18 +08:00
| Composable | Description |
2026-05-24 22:07:37 +08:00
| -------------------------- | ------------------------------------------------------------------------------------- |
| `useInput(handler, opts?)` | Handle keyboard input — receives `(input, key)` with modifier and arrow key detection |
| `useFocus(opts?)` | Component-level focus — returns `{ isFocused, focus }` |
| `useFocusManager()` | App-level focus control — `focusNext()` , `focusPrevious()` , `focus(id)` |
2026-05-30 23:32:22 +08:00
| `useApp()` | App lifecycle — `{ exit(error?), waitUntilRenderFlush() }` |
2026-05-24 22:07:37 +08:00
| `useTerminalSize()` | Reactive terminal dimensions — `{ columns, rows }` |
| `useStdin()` | Access stdin stream and raw mode control |
| `useStdout()` | Write directly to stdout |
| `useStderr()` | Write directly to stderr |
## Testing
The `@vue-tui/testing` package renders components in an isolated environment and lets you simulate input and assert visual output:
2026-05-24 18:14:06 +08:00
```bash
2026-05-24 22:07:37 +08:00
npm install -D @vue-tui/testing
```
```tsx
2026-05-27 15:03:18 +08:00
import { defineComponent , shallowRef } from "vue" ;
2026-05-24 22:07:37 +08:00
import { expect , test } from "vitest" ;
import { render } from "@vue-tui/testing" ;
import { Box , Text , useInput } from "@vue-tui/runtime" ;
test ( "counter responds to + and - keys" , async () => {
const Counter = defineComponent (() => {
2026-05-27 15:03:18 +08:00
const count = shallowRef ( 0 );
2026-05-24 22:07:37 +08:00
useInput (( input ) => {
if ( input === "+" ) count . value ++ ;
if ( input === "-" ) count . value -- ;
});
return () => (
< Box >
< Text > Count : { count . value }</ Text >
</ Box >
);
});
const { lastFrame , stdin } = await render ( Counter );
expect ( lastFrame ()). toContain ( "Count: 0" );
await stdin . write ( "+" );
expect ( lastFrame ()). toContain ( "Count: 1" );
await stdin . write ( "-" );
expect ( lastFrame ()). toContain ( "Count: 0" );
});
2026-05-24 18:14:06 +08:00
```
2026-05-24 22:07:37 +08:00
## Development
Requires [pnpm ](https://pnpm.io/ ) and Node.js 22+.
2026-05-24 18:14:06 +08:00
```bash
2026-05-24 22:07:37 +08:00
pnpm install # install dependencies
vp run ready # lint, typecheck, test, and build (the full check)
vp run -r test # run tests across all packages
vp run -r build # build all packages
vue-tui dev # start an example with HMR
2026-05-24 18:14:06 +08:00
```
2026-05-27 15:13:59 +08:00
## Contributing
Contributions welcome! vue-tui is evolving fast — please open an issue before starting large changes. If you use AI tools, disclose it in your PR and make sure you've reviewed and tested everything before submitting.
2026-05-24 18:14:06 +08:00
## Credits
2026-05-27 15:03:18 +08:00
vue-tui is built on the ideas pioneered by [Ink ](https://github.com/vadimdemedes/ink ) — component model, yoga-based layout, focus system, and rendering pipeline — adapted to Vue's philosophy. Thanks to [Vadim Demedes ](https://github.com/vadimdemedes ), [Sindre Sorhus ](https://github.com/sindresorhus ), and the [Ink contributors ](https://github.com/vadimdemedes/ink/graphs/contributors ).
2026-05-24 22:07:37 +08:00
## License
MIT