vue-tui
Health Warn
- No license — Repository has no license file
- Description — Repository has a description
- Active repo — Last push 0 days ago
- Community trust — 56 GitHub stars
Code Pass
- Code scan — Scanned 12 files during light audit, no dangerous patterns found
Permissions Pass
- Permissions — No dangerous permissions requested
No AI report is available for this listing yet.
Terminal UI framework built on Vue and Vite. Components, layout, focus, HMR, and testing out of the box.
vue-tui
Early stage — under active development. Bug reports welcome, but not recommended for production use yet.
Vue for the terminal. Build interactive CLI apps with components, flexbox, and HMR.
- Vue SFC & JSX — write terminal UIs with
<template>, TSX, or both - Flexbox layout — powered by Yoga, the same engine behind React Native
- Focus system — built-in focus management with Tab navigation
- Hot module replacement — instant feedback while developing
- First-class testing — render components, simulate input, assert frames
Packages
@vue-tui/runtime— The core framework. A custom Vue 3 renderer that targets the terminal instead of the DOM. Provides components (Box,Text,Static, etc.), composables (useInput,useFocus,useExit, etc.), and a yoga-based flexbox layout engine.@vue-tui/cli— Development tool. Runvue-tui devto start your app with Vite-powered HMR — edit a.vuefile and see the terminal update instantly.@vue-tui/testing— Test harness. Render components in an isolated fake terminal, simulate keyboard input, and assert on visual output frame by frame.
Quick Example
// src/main.ts
import { createApp } from "@vue-tui/runtime";
import App from "./App.vue";
createApp(App).mount();
<!-- src/App.vue -->
<script setup lang="ts">
import { shallowRef } from "vue";
import { Box, Text, useInput } from "@vue-tui/runtime";
const count = shallowRef(0);
useInput((input) => {
if (input === "+") count.value++;
if (input === "-") count.value--;
});
</script>
<template>
<Box>
<Text>Count: </Text>
<Text bold color="green">{{ count }}</Text>
<!-- try changing this color -->
<Text dimColor> (+/- to change)</Text>
</Box>
</template>
Examples
| Example | Description |
|---|---|
basic-template |
Vue SFC with <template> syntax |
basic-jsx |
Same app in TSX |
coding-agent |
AI coding agent with LLM streaming and interactive UI |
flappy-bird |
Physics-based terminal game with reactive state and borders |
Getting Started
npx tiged vuejs-ai/vue-tui-starter my-app
cd my-app
npm install
npm run dev
That's it — try changing the color or text in App.vue and watch the terminal update instantly while keeping your component state.
To build and run:
npm run preview
Components
| Component | Description |
|---|---|
<Box> |
Flexbox container — direction, wrap, align, justify, gap, padding, margin, borders, background |
<Text> |
Styled text — color, bold, italic, underline, strikethrough, dimColor, wrap/truncate modes |
<Spacer> |
Expands to fill available space (flex-grow: 1) |
<Newline> |
Inserts line breaks (configurable count) |
<Static> |
Renders a list of items once, above the redrawn region |
<Transform> |
Applies a string transform function to each rendered line |
Hooks
| Hook | Description |
|---|---|
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) |
useExit() |
Programmatic app exit — returns exit(error?) |
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:
npm install -D @vue-tui/testing
import { defineComponent, ref } from "vue";
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(() => {
const count = ref(0);
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");
});
Development
Requires pnpm and Node.js 22+.
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
Caveats
- vue-tui enables raw mode by default so the terminal won't echo keystrokes into your UI.
- Ctrl+C still exits —
exitOnCtrlCdefaults totrue. - For pure-output tools that don't need input suppression, pass
rawMode: falsetomount().
Credits
vue-tui started as a Vue port of Ink, the library that proved terminal UIs could be built with the same component patterns we use on the web. The component model, yoga-based layout, focus system, rendering pipeline — all of it originates in Ink's design, adapted to follow Vue's philosophy and conventions. Thank you to Vadim Demedes, Sindre Sorhus, and the Ink contributors for creating such a solid foundation.
License
MIT
Reviews (0)
Sign in to leave a review.
Leave a reviewNo results found