Files
vue-tui/README.md
T
Yunfei He e87274fcda docs: replace manual install with tiged starter in Getting Started
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-24 22:13:59 +08:00

6.5 KiB

vue-tui

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

Quick Example

<script lang="ts">
import { shallowRef, defineComponent } from "vue";
import { Box, Text, useInput } from "@vue-tui/runtime";

export default defineComponent({
  components: { Box, Text },
  setup() {
    const count = shallowRef(0);

    useInput((input) => {
      if (input === "+") count.value++;
      if (input === "-") count.value--;
    });

    return { count };
  },
});
</script>

<template>
  <Box>
    <Text>Count: </Text>
    <Text bold color="green">{{ count }}</Text>
    <Text dimColor> (+/- to change)</Text>
  </Box>
</template>

Getting Started

npx tiged vuejs-ai/vue-tui-starter my-app
cd my-app
npm install
npm run dev

That's it — edit src/App.vue and see changes instantly with HMR.

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");
});

Examples

Example Description
basic-template Vue SFC with <template> syntax
basic-jsx Same app in TSX
flappy-bird Physics-based game with reactive state and borders

Packages

Package Description
@vue-tui/runtime Core renderer — components, hooks, layout engine
@vue-tui/testing Test harness — render(), frame assertions, input simulation
@vue-tui/cli Dev tool — vue-tui dev with Vite HMR

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

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