https://github.com/oneeyed1366/wolf-tui
Framework-agnostic Terminal UI library — React, Vue, Angular, SolidJS, Svelte. JSX/template syntax, Flexbox/Grid layouts (Taffy), CSS-like styling.
https://github.com/oneeyed1366/wolf-tui
angular cli css flexbox jsx nodejs react solidjs svelte terminal terminal-ui tui tui-framework typescript vue
Last synced: about 2 months ago
JSON representation
Framework-agnostic Terminal UI library — React, Vue, Angular, SolidJS, Svelte. JSX/template syntax, Flexbox/Grid layouts (Taffy), CSS-like styling.
- Host: GitHub
- URL: https://github.com/oneeyed1366/wolf-tui
- Owner: OneEyed1366
- License: mit
- Created: 2026-02-25T07:14:53.000Z (4 months ago)
- Default Branch: master
- Last Pushed: 2026-04-14T13:27:00.000Z (3 months ago)
- Last Synced: 2026-04-14T13:27:43.888Z (3 months ago)
- Topics: angular, cli, css, flexbox, jsx, nodejs, react, solidjs, svelte, terminal, terminal-ui, tui, tui-framework, typescript, vue
- Language: TypeScript
- Size: 2.92 MB
- Stars: 1
- Watchers: 0
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- Contributing: CONTRIBUTING.md
- License: license
- Agents: AGENTS.md
Awesome Lists containing this project
README
# wolf-tui
### Write CLI apps with your web framework — React, Vue, Angular, Solid, or Svelte
[](https://opensource.org/licenses/MIT)
[](https://nodejs.org/)
[Quick Start](#quick-start) · [Packages](#packages) · [Components](#components) · [Styling](#styling) · [Testing](#testing) · [Architecture](#architecture) · [Development](#development)
---
> [!IMPORTANT]
> **What this installs:**
>
> - Native `.node` bindings for the [Taffy](https://github.com/DioxusLabs/taffy) layout engine (Rust → Node via napi-rs, not WASM)
> - Prebuilt for Linux (x64/arm64), macOS (Intel/Apple Silicon), Windows
> - No network calls, no telemetry, no files written outside your project
>
> **Uninstall:** `npm remove @wolf-tui/react @wolf-tui/plugin` (substitute your adapter)
## The Problem
Building terminal UIs means choosing between raw ANSI escape codes or framework-specific tools locked to one ecosystem. If you know React, you can use [Ink](https://github.com/vadimdemedes/ink) — but there's nothing for Vue, Angular, Solid, or Svelte. And Ink's layout engine (Yoga) only supports Flexbox.
wolf-tui started as a fork of Ink, then expanded: five framework adapters sharing one layout engine ([Taffy](https://github.com/DioxusLabs/taffy) — Flexbox + CSS Grid), one component library, and one styling pipeline (Tailwind, SCSS, CSS Modules). Write a component once, render it in any adapter.
---
## Quick Start
### Scaffold a new project
```bash
npm create wolf-tui
```
The CLI walks you through framework, bundler, and styling choices — generates a ready-to-run project. See [create-wolf-tui](packages/create-wolf-tui/README.md) for flags and options.
### Add to an existing project
Pick your framework:
### React
```bash
npm install @wolf-tui/react && npm install -D @wolf-tui/plugin
```
```tsx
import { render, Box, Text } from '@wolf-tui/react'
function App() {
return (
Hello from wolf-tui!
)
}
render()
```
Vue
```bash
npm install @wolf-tui/vue && npm install -D @wolf-tui/plugin
```
```vue
import { Box, Text } from '@wolf-tui/vue'
Hello from wolf-tui!
```
```ts
import { render } from '@wolf-tui/vue'
import App from './App.vue'
render(App)
```
Angular
```bash
npm install @wolf-tui/angular && npm install -D @wolf-tui/plugin
```
```typescript
import { Component } from '@angular/core'
import { BoxComponent, TextComponent } from '@wolf-tui/angular'
@Component({
standalone: true,
imports: [BoxComponent, TextComponent],
template: `
Hello from wolf-tui!
`,
})
export class AppComponent {}
```
```ts
import { renderWolfie } from '@wolf-tui/angular'
import { AppComponent } from './app.component'
renderWolfie(AppComponent)
```
SolidJS
```bash
npm install @wolf-tui/solid && npm install -D @wolf-tui/plugin
```
```tsx
import { render, Box, Text } from '@wolf-tui/solid'
function App() {
return (
Hello from wolf-tui!
)
}
render(App, { stdout: process.stdout, stdin: process.stdin })
```
Svelte
```bash
npm install @wolf-tui/svelte && npm install -D @wolf-tui/plugin
```
```svelte
import { Box, Text } from '@wolf-tui/svelte'
Hello from wolf-tui!
```
```ts
import { render } from '@wolf-tui/svelte'
import App from './App.svelte'
render(App)
```
Svelte requires `--conditions=browser` at runtime and a build step. See the [Svelte adapter README](packages/svelte/README.md) for full setup.
Each adapter has a detailed README with full API docs, Vite/esbuild/webpack configuration, and component reference.
---
## Packages
| Package | Description | Docs |
| ------------------------------------------------------------------- | ------------------------------------------ | ---------------------------------------------- |
| [create-wolf-tui](packages/create-wolf-tui/README.md) | Project scaffolding CLI | [README](packages/create-wolf-tui/README.md) |
| [@wolf-tui/core](internal/core/README.md) | Layout engine, DOM, renderer | Core |
| [@wolf-tui/react](packages/react/README.md) | React 19+ adapter | [README](packages/react/README.md) |
| [@wolf-tui/vue](packages/vue/README.md) | Vue 3.5+ adapter | [README](packages/vue/README.md) |
| [@wolf-tui/angular](packages/angular/README.md) | Angular 17+ adapter | [README](packages/angular/README.md) |
| [@wolf-tui/solid](packages/solid/README.md) | SolidJS 1.9+ adapter | [README](packages/solid/README.md) |
| [@wolf-tui/svelte](packages/svelte/README.md) | Svelte 5+ adapter | [README](packages/svelte/README.md) |
| [@wolf-tui/testing-library](packages/testing-library/README.md) | Framework-agnostic headless testing utils | [README](packages/testing-library/README.md) |
| [@wolf-tui/plugin](packages/plugin/README.md) | Build plugin (Vite/esbuild/webpack/Rollup) | [README](packages/plugin/README.md) |
| [@wolf-tui/typescript-plugin](packages/typescript-plugin/README.md) | TypeScript plugin for CSS module types | [README](packages/typescript-plugin/README.md) |
| [@wolf-tui/css-parser](internal/css-parser/README.md) | CSS/SCSS/LESS/Stylus parser | Internal |
---
## Components
All adapters share the same component set — same visual output across all 5 frameworks via the shared WNode render architecture.
| Category | Components |
| ----------- | ---------------------------------------------------------------------------------------------------------------------------------------------------- |
| **Layout** | `Box`, `Text`, `Newline`, `Spacer`, `Static`, `Transform`, `ScrollView`, `Table` |
| **Display** | `Alert`, `Badge`, `Spinner`, `ProgressBar`, `StatusMessage`, `ErrorOverview`, `Gradient`, `BigText`, `Timer`, `TreeView`, `JsonViewer`, `FilePicker` |
| **Input** | `TextInput`, `PasswordInput`, `EmailInput`, `ConfirmInput`, `Select`, `MultiSelect`, `Combobox` |
| **Lists** | `OrderedList`, `UnorderedList` |
Plus composables/hooks: `useInput`, `useFocus`, `useFocusManager`, stream access, screen reader detection.
Component reference — Description + Key features
Adapted (where applicable) from the [ink-\* community ecosystem](https://github.com/vadimdemedes/ink/pull/922) (Gradient from [ink-gradient](https://github.com/sindresorhus/ink-gradient), BigText from [ink-big-text](https://github.com/sindresorhus/ink-big-text)). Available in all 5 adapters with identical APIs.
**Layout**
| Component | Description | Key features |
| ------------ | ------------------------------------------- | ---------------------------------------------------------- |
| `Box` | Flexbox/Grid layout container | All CSS-like flex props, `style` object, `className` |
| `Text` | Styled inline text | Color, bold/italic/underline, wrap modes |
| `Newline` | Empty lines | `count` prop |
| `Spacer` | Fills remaining flex space | Pushes siblings apart in flex containers |
| `Static` | Renders items once, skips re-renders | Append-only logs, scroll-back history |
| `Transform` | Transforms rendered text of children | `transform: (line, idx) => string` |
| `ScrollView` | Fixed-height viewport with clipped overflow | Built-in arrow / PageUp / PageDown / Home / End navigation |
| `Table` | Box-drawing table for tabular data | `ink-table` parity, themable borders/cells, column subset |
**Display**
| Component | Description | Key features |
| --------------- | -------------------------------------- | -------------------------------------------------------------- |
| `Alert` | Boxed alert message | `variant`: `success` / `error` / `warning` / `info` + title |
| `Badge` | Inline coloured label | `color` prop |
| `Spinner` | Animated loading spinner | 80+ `type`s (dots, line, arc, …), optional `label` |
| `ProgressBar` | Horizontal progress bar | `value` 0–100, custom characters, themable colors |
| `StatusMessage` | One-line status with icon | `variant`: `success` / `error` / `warning` / `info` |
| `ErrorOverview` | Formatted error display | Pretty stack trace, source frame highlight |
| `Gradient` | Coloured text gradient | 13 presets or custom hex stops, per-character interpolation |
| `BigText` | ASCII-art figlet-style banner | `cfonts` engine, multiple fonts, gradients, alignment |
| `Timer` | Count-up, countdown, or stopwatch | Lap recording, configurable format, drift-resistant |
| `TreeView` | Hierarchical tree with expand/collapse | Single/multi-select, async lazy loading, virtual scroll |
| `JsonViewer` | Interactive JSON tree viewer | 16 value types, syntax colouring, circular-reference detection |
| `FilePicker` | Filesystem browser with filter mode | Multi-select, symlinks, directory navigation |
**Input**
| Component | Description | Key features |
| --------------- | ----------------------------------- | ------------------------------------------------------- |
| `TextInput` | Single-line text field | `onChange` / `onSubmit`, placeholder, mask, suggestions |
| `PasswordInput` | Masked text input | Configurable mask character |
| `EmailInput` | Email field with domain suggestions | Auto-completes top-100 email domains |
| `ConfirmInput` | Yes / No prompt | y / n keys, customizable defaults |
| `Select` | Single-selection picker | Keyboard nav, themed indicator, `options` array |
| `MultiSelect` | Multi-selection picker | Toggle with space, submit with enter |
| `Combobox` | Fuzzy-search autocomplete dropdown | Two-pass fzf-style matching, cursor nav, autofill |
**Lists**
| Component | Description | Key features |
| --------------- | ------------- | ---------------------------- |
| `OrderedList` | Numbered list | `OrderedListItem` children |
| `UnorderedList` | Bulleted list | `UnorderedListItem` children |
```tsx
// React example
import { Timer, JsonViewer, FilePicker, Table, Gradient, BigText } from '@wolf-tui/react'
// Timer with countdown
// Interactive JSON viewer
// File picker with multi-select
console.log(paths)} />
// Table with box-drawing borders
// Gradient text — by preset name, or custom stops
wolf-tui in color
Hand-picked stops
// BigText figlet-style banner
```
See individual adapter READMEs for API details and prop reference.
---
## Styling
```tsx
// Inline styles
Styled text
// Tailwind CSS (v3.4 / v4.1)
Styled with Tailwind
```
| Method | Setup |
| ---------------- | --------------------------------- |
| Inline styles | Works out of the box |
| Tailwind CSS | PostCSS + `@wolf-tui/plugin` |
| CSS Modules | `*.module.css` imports |
| SCSS/LESS/Stylus | Preprocessor + `@wolf-tui/plugin` |
All CSS approaches resolve to terminal styles at build time — no runtime CSS engine.
Units and colors
**Relative units:**
| Unit | Terminal conversion |
| ----------- | --------------------------------------- |
| `px` | value / 4 cells |
| `rem` | value × 4 cells (1rem = 16px = 4 cells) |
| `%` | Dynamic (parent-based) |
| `vw` / `vh` | Terminal columns / rows |
| `ch` | 1 cell per ch |
**Color support:**
- 140+ named CSS colors mapped to ANSI
- Hex: `#fff`, `#ffffff`
- RGB/RGBA: `rgb(255 0 0)`, `rgba(255, 0, 0, 0.5)`
- OKLCH, HSL, LAB, LCH via colorjs.io
- Tailwind arbitrary values: `text-[cyan]`, `bg-[#ff0]`
---
## Testing
Every adapter ships a `/testing` subpath that swaps the real terminal for virtual streams, so components can be exercised headlessly under Vitest, Jest, or Node's test runner. The same API works across all five frameworks — pick your adapter's import and the rest is identical.
```tsx
import { afterEach, test, expect } from 'vitest'
import {
render,
cleanup,
KEYS,
delay,
stripAnsi,
} from '@wolf-tui/react/testing'
import { App } from './App'
afterEach(cleanup)
test('navigates the menu', async () => {
const { stdin, lastFrame } = render(, { columns: 80, rows: 24 })
await stdin.write(KEYS.DOWN)
await stdin.write(KEYS.ENTER)
await delay(100)
expect(stripAnsi(lastFrame() ?? '')).toContain('Selection: Option B')
})
```
Scaffold a project with `npm create wolf-tui -- --test` to get Vitest, `@wolf-tui/testing-library`, and a pre-wired `test/setup.ts` out of the box. See [@wolf-tui/testing-library](packages/testing-library/README.md) for the full API.
---
## Architecture
```
┌──────────────────┐
│ @wolf-tui/core │ Taffy layout, virtual DOM, ANSI renderer
│ (napi-rs) │ native .node bindings
└────────┬─────────┘
│
┌────────┴─────────┐
│ @wolf-tui/shared │ render scheduler, shared render functions,
│ │ input parsing, theme system
└────────┬─────────┘
│
┌─────┼─────┬─────────┬──────────┐
│ │ │ │ │
React Vue Angular SolidJS Svelte
```
Each adapter maps its framework's component model to the shared virtual DOM. Taffy computes layout, the core renderer produces ANSI output. A visual bug either affects all adapters (render function issue) or one adapter (integration issue) — two-step debug path.
Layout engine: Taffy
wolf-tui uses [Taffy](https://github.com/DioxusLabs/taffy) for layout computation. Taffy supports both Flexbox and CSS Grid — Yoga (used by Ink and React Native) only supports Flexbox.
Integration details:
- Native Node.js bindings via napi-rs (not WASM — no startup penalty)
- Supports `calc()` values
- Prebuilt for Linux (x64/arm64), macOS (Intel/Apple Silicon), Windows
Performance
**Incremental rendering:** All adapters render only changed terminal lines per frame, not the full screen. Disable for headless testing:
```ts
render(, { incrementalRendering: false })
```
**React Compiler:** `@wolf-tui/react` ships pre-compiled with the [React Compiler](https://react.dev/learn/react-compiler) — all library components skip re-renders when props haven't changed. To apply to your own components:
```bash
npm install -D babel-plugin-react-compiler
```
```ts
// vite.config.ts
import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react'
import { wolfie } from '@wolf-tui/plugin/vite'
export default defineConfig({
plugins: [
react({
babel: {
plugins: [['babel-plugin-react-compiler', {}]],
},
}),
wolfie('react'),
],
})
```
Requires React 19+.
---
## Development
```bash
git clone
cd wolf-tui
pnpm install
pnpm dev
```
| Command | Description |
| ---------------- | ------------------------------------- |
| `pnpm dev` | Watch mode for all packages |
| `pnpm build` | Build all packages |
| `pnpm test` | Run all unit tests |
| `pnpm test:e2e` | E2E screenshot tests (20 tests, ~38s) |
| `pnpm lint` | ESLint check |
| `pnpm typecheck` | TypeScript type checking |
See [CONTRIBUTING.md](CONTRIBUTING.md) for development guidelines.
---
## Acknowledgments
This project started as a fork of [Ink](https://github.com/vadimdemedes/ink) by Vadim Demedes. The React package (`@wolf-tui/react`) builds upon Ink's foundation and includes components from the ink-\* ecosystem.
## License
MIT