wolf-tui Svelte Themes

Wolf Tui

Framework-agnostic Terminal UI library — React, Vue, Angular, SolidJS, Svelte. JSX/template syntax, Flexbox/Grid layouts (Taffy), CSS-like styling.

wolf-tui

Write CLI apps with your web framework — React, Vue, Angular, Solid, or Svelte

Quick Start · Packages · Components · Styling · Architecture · Development


[!IMPORTANT] What this installs:

  • Native .node bindings for the 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 — 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 — 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

npm create wolf-tui

The CLI walks you through framework, bundler, and styling choices — generates a ready-to-run project. See create-wolf-tui for flags and options.

Add to an existing project

Pick your framework:

React

npm install @wolf-tui/react && npm install -D @wolf-tui/plugin
import { render, Box, Text } from '@wolf-tui/react'

function App() {
    return (
        <Box style={{ flexDirection: 'column', padding: 1 }}>
            <Text style={{ color: 'green' }}>Hello from wolf-tui!</Text>
        </Box>
    )
}

render(<App />)
Vue
npm install @wolf-tui/vue && npm install -D @wolf-tui/plugin
<script setup>
import { Box, Text } from '@wolf-tui/vue'
</script>

<template>
    <Box :style="{ flexDirection: 'column', padding: 1 }">
        <Text :style="{ color: 'green' }">Hello from wolf-tui!</Text>
    </Box>
</template>
import { render } from '@wolf-tui/vue'
import App from './App.vue'

render(App)
Angular
npm install @wolf-tui/angular && npm install -D @wolf-tui/plugin
import { Component } from '@angular/core'
import { BoxComponent, TextComponent } from '@wolf-tui/angular'

@Component({
    standalone: true,
    imports: [BoxComponent, TextComponent],
    template: `
        <w-box [style]="{ flexDirection: 'column', padding: 1 }">
            <w-text [style]="{ color: 'green' }">Hello from wolf-tui!</w-text>
        </w-box>
    `,
})
export class AppComponent {}
import { renderWolfie } from '@wolf-tui/angular'
import { AppComponent } from './app.component'

renderWolfie(AppComponent)
SolidJS
npm install @wolf-tui/solid && npm install -D @wolf-tui/plugin
import { render, Box, Text } from '@wolf-tui/solid'

function App() {
    return (
        <Box style={{ flexDirection: 'column' }}>
            <Text style={{ color: 'green' }}>Hello from wolf-tui!</Text>
        </Box>
    )
}

render(App, { stdout: process.stdout, stdin: process.stdin })
Svelte
npm install @wolf-tui/svelte && npm install -D @wolf-tui/plugin
<!-- App.svelte -->
<script>
import { Box, Text } from '@wolf-tui/svelte'
</script>

<Box style={{ flexDirection: 'column', padding: 1 }}>
    <Text style={{ color: 'green', fontWeight: 'bold' }}>Hello from wolf-tui!</Text>
</Box>
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 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 Project scaffolding CLI README
@wolf-tui/core Layout engine, DOM, renderer Core
@wolf-tui/react React 19+ adapter README
@wolf-tui/vue Vue 3.5+ adapter README
@wolf-tui/angular Angular 17+ adapter README
@wolf-tui/solid SolidJS 1.9+ adapter README
@wolf-tui/svelte Svelte 5+ adapter README
@wolf-tui/plugin Build plugin (Vite/esbuild/webpack/Rollup) README
@wolf-tui/typescript-plugin TypeScript plugin for CSS module types README
@wolf-tui/css-parser CSS/SCSS/LESS/Stylus parser Internal

Components

All adapters share the same component set:

Category Components
Layout Box, Text, Spacer, Newline, Static, Transform
Display Alert, Badge, Spinner, ProgressBar, StatusMessage, ErrorOverview
Input TextInput, PasswordInput, EmailInput, ConfirmInput, Select, MultiSelect
Lists OrderedList, UnorderedList
Community Timer, TreeView, Combobox, JsonViewer, FilePicker

Plus composables/hooks: useInput, useFocus, useFocusManager, stream access, screen reader detection.

Community components — Timer, TreeView, Combobox, JsonViewer, FilePicker

Adapted from the ink-* community ecosystem, available in all 5 adapters:

Component Description Key features
Timer Count-up, countdown, stopwatch Lap recording, configurable format, drift-resistant
TreeView Hierarchical tree with expand/collapse Single/multi-select, async lazy loading, virtual scroll
Combobox Fuzzy-search autocomplete dropdown Two-pass fzf-style matching, cursor nav, autofill
JsonViewer Interactive JSON tree viewer 16 value types, syntax coloring, circular detection
FilePicker Filesystem browser with filter Multi-select, symlink support, directory navigation
// React example
import { Timer, TreeView, Combobox, JsonViewer, FilePicker } from '@wolf-tui/react'

// Timer with countdown
<Timer variant="countdown" durationMs={60000} format="human" />

// Interactive JSON viewer
<JsonViewer data={{ users: [{ name: 'Alice' }] }} defaultExpandDepth={2} />

// File picker with multi-select
<FilePicker initialPath="." multiSelect onSelect={(paths) => console.log(paths)} />

All community components use the shared WNode render architecture — same visual output across all 5 frameworks.

See individual adapter READMEs for API details and prop reference.


Styling

// Inline styles
<Box style={{ flexDirection: 'column', padding: 1, gap: 1 }}>
    <Text style={{ color: 'green', fontWeight: 'bold' }}>Styled text</Text>
</Box>

// Tailwind CSS (v3.4 / v4.1)
<Box className="flex-col p-4 gap-2">
    <Text className="text-green-500 font-bold">Styled with Tailwind</Text>
</Box>
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]

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 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:

render(<App />, { incrementalRendering: false })

React Compiler: @wolf-tui/react ships pre-compiled with the React Compiler — all library components skip re-renders when props haven't changed. To apply to your own components:

npm install -D babel-plugin-react-compiler
// 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

git clone <repo-url>
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 for development guidelines.


Acknowledgments

This project started as a fork of Ink by Vadim Demedes. The React package (@wolf-tui/react) builds upon Ink's foundation and includes components from the ink-* ecosystem.

License

MIT

Top categories

Loading Svelte Themes