What if building terminal applications felt like building web applications?
That question led me to create SvelTUI - a terminal UI framework that brings Svelte 5's elegant reactive programming model to the command line.
The Problem with Traditional Terminal UIs
If you've ever built a terminal UI, you know the pain:
- Imperative spaghetti: Manually tracking cursor positions, clearing regions, redrawing elements
- Flickering: Full screen redraws cause visible flashing
- Layout nightmares: Calculating x/y coordinates for every element
- State management: Keeping UI in sync with data requires careful orchestration
Web development solved these problems years ago with declarative components, reactive state, and flexbox. Why can't terminals have the same?
Enter SvelTUI
Here's a complete, interactive counter application:
<script>
import { Box, Text, keyboard } from 'sveltui'
let count = $state(0)
keyboard.onKey('Space', () => count++)
</script>
<Box border="rounded" borderColor={0x06} padding={1}>
<Text text="Press Space!" color={0x0a} />
<Text text={`Count: ${count}`} color={0x0b} />
</Box>
That's it. When you press Space, count increments, and the display updates instantly. No manual redrawing. No flicker. Just reactive state doing its thing.
How It Works
SvelTUI's architecture is unconventional but elegant:
1. Svelte in Happy DOM
Svelte needs a DOM to work. Instead of fighting this, we embrace it. Happy DOM provides a lightweight DOM implementation. Svelte doesn't know it's not in a browser.
2. Yoga for Layouts
Yoga is Facebook's cross-platform flexbox implementation (used in React Native). It calculates layouts based on flexbox rules:
<Box
flexDirection="row"
justifyContent="space-between"
alignItems="center"
padding={2}
gap={1}
>
<Text text="Left" />
<Text text="Center" />
<Text text="Right" />
</Box>
Real flexbox. In a terminal. Finally.
3. Typed Array Buffers
Component state lives in typed arrays - one for characters, one for foreground colors, one for background colors, one for style flags. This is cache-friendly and enables efficient comparison.
4. Differential Rendering
Every render, we compare the new buffer to the previous one. Only cells that actually changed get written to the terminal. This eliminates flicker completely.
5. Reactive On-Demand
There's no setInterval running at 60fps. Updates happen synchronously when reactive state changes. When nothing changes, nothing happens - zero CPU usage.
Features
Components
-
Box- Container with flexbox layout, borders, backgrounds -
Text- Styled text with colors and formatting
Layout (via Yoga)
-
flexDirection,justifyContent,alignItems -
padding,margin,gap - Percentage and fixed dimensions
-
flexGrowfor fluid layouts
Keyboard API
<script>
import { keyboard } from 'sveltui'
// Reactive - use in templates
keyboard.lastKey
// Imperative - use for actions
keyboard.onKey('Enter', () => submit())
keyboard.onKey(['ArrowUp', 'k'], () => scrollUp())
</script>
Theming
Built-in themes: default, dracula, nord, monokai, solarized
<script>
import { getTheme } from 'sveltui'
const theme = getTheme()
theme().setTheme('dracula')
</script>
Semantic Variants
<Box variant="success" border="rounded">
<Text text="Operation completed" variant="success" />
</Box>
Getting Started
# Create a new project
bunx @rlabs-inc/sveltui create my-app
# Choose a template (minimal, counter, or dashboard)
cd my-app
bun install
bun run dev
The dashboard template showcases layouts, live data, scrolling, and theming.
The Svelte 5 Advantage
Why Svelte 5 specifically?
Runes are perfect for this. $state creates fine-grained reactive signals. When count changes in our counter example, Svelte knows exactly what depends on it and updates only that.
No virtual DOM overhead. Svelte compiles reactivity away. The runtime is minimal. Combined with our differential rendering, updates are essentially free.
Familiar patterns. If you know Svelte, you know SvelTUI. Same components, same reactivity, same lifecycle.
Current Status
SvelTUI is early stage but functional. The architecture is solid, the core features work well.
What's working:
- Box and Text components
- Full flexbox layout
- Keyboard handling
- Focus and scroll management
- Theming system
- True 24-bit color
What's planned:
- Input component
- List/Table components
- Progress bars
- Animation primitives
- More themes
Try It Out
bunx @rlabs-inc/sveltui create my-app --template dashboard
GitHub: github.com/RLabs-Inc/sveltui
npm: @rlabs-inc/sveltui
I'd love to hear what you think. What would you build with this? What components do you need? Drop a comment or open an issue on GitHub!
SvelTUI is MIT licensed and open source. Contributions welcome!
Top comments (0)