⚠️ Early Stage - SvelTUI is functional and actively developed, but still in early stages. APIs may change. We'd love your feedback and contributions!
Build beautiful terminal applications with Svelte 5
SvelTUI is a terminal UI framework that brings Svelte's elegant reactive programming model to the command line. Write declarative components, enjoy instant reactivity, and build responsive terminal interfaces with the same developer experience you love from web development.
<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>
Unlike traditional terminal UI libraries that redraw at fixed intervals, SvelTUI only updates what actually changed, when it changes. Press a key and see the result instantly - no frame delay, no flickering, no wasted CPU cycles.
Built from the ground up for Svelte 5's new reactivity system. Use $state, $derived, and $effect naturally - they just work in the terminal.
Full CSS flexbox support via Facebook's Yoga layout engine. Finally, sane layouts in the terminal.
Differential rendering updates only the cells that changed. Your UI stays rock solid.
Box, Text, and more coming soon# Using the CLI (recommended)
bunx @rlabs-inc/sveltui create my-app
cd my-app
bun install
bun run dev
The CLI offers three starter templates:
# Skip template selection with --template
bunx @rlabs-inc/sveltui create my-app --template dashboard
mkdir my-app && cd my-app
bun init -y
bun add sveltui svelte
Create src/main.ts:
import { mount } from 'sveltui'
import { mount as mountComponent } from 'svelte'
import App from './App.svelte'
mount(() => {
mountComponent(App, { target: document.body })
}, { fullscreen: true })
Create src/App.svelte:
<script>
import { Box, Text } from 'sveltui'
</script>
<Box width="100%" height="100%" padding={2}>
<Box border="rounded" borderColor={0x06} padding={1}>
<Text text="Hello, Terminal!" color={0x0a} />
</Box>
</Box>
Container component with flexbox layout, borders, and background colors.
<Box
border="rounded"
borderColor={0x06}
backgroundColor={0x000033}
width={40}
height={10}
padding={1}
>
<Text text="Content inside a box" />
</Box>
Props:
| Prop | Type | Description |
|---|---|---|
border |
'none' | 'single' | 'double' | 'rounded' | 'bold' | 'dashed' | 'dotted' |
Border style |
borderColor |
number | string |
Border color (hex number or CSS color) |
backgroundColor |
number | string |
Background color |
width, height |
number | string |
Dimensions (number for chars, string like "50%" for percentage) |
padding, paddingX, paddingY |
number |
Inner padding |
margin, marginX, marginY |
number |
Outer margin |
flexDirection |
'row' | 'column' |
Main axis direction |
flexGrow |
number |
How much to grow relative to siblings |
justifyContent |
'flex-start' | 'center' | 'flex-end' | 'space-between' |
Main axis alignment |
alignItems |
'flex-start' | 'center' | 'flex-end' | 'stretch' |
Cross axis alignment |
gap |
number |
Space between children |
focusable |
boolean |
Whether the box can receive focus |
variant |
'primary' | 'secondary' | 'accent' | 'success' | 'warning' | 'danger' | 'info' |
Theme-based styling |
Renders styled text content.
<Text
text="Hello World"
color={0x00ff00}
bold
/>
⚠️ Important: Always use the
textprop, not children. Due to how Svelte handles children rendering,<Text text="Hello" />works correctly with reactivity, but<Text>Hello</Text>does not update reactively.
Props:
| Prop | Type | Description |
|---|---|---|
text |
string |
The text content to display (required) |
color |
number | string |
Text color (hex number or CSS color) |
bold |
boolean |
Bold text |
italic |
boolean |
Italic text |
underline |
boolean |
Underlined text |
dim |
boolean |
Dimmed text |
variant |
'primary' | 'secondary' | 'accent' | 'success' | 'warning' | 'danger' | 'info' |
Theme-based color |
muted |
boolean |
Use theme's muted text color |
bright |
boolean |
Use theme's bright text color |
SvelTUI provides a hybrid keyboard API - reactive state for UI display, imperative callbacks for event handling.
<script>
import { keyboard } from 'sveltui'
</script>
<!-- Automatically updates when any key is pressed -->
<Text text={`Last key: ${keyboard.lastKey}`} />
<script>
import { keyboard } from 'sveltui'
import { onDestroy } from 'svelte'
// Single key
const unsub = keyboard.onKey('Enter', () => {
console.log('Enter pressed!')
})
// Multiple keys
const unsub2 = keyboard.onKey(['ArrowUp', 'k'], () => {
scrollUp()
})
// All keys
const unsub3 = keyboard.on((event) => {
console.log(event.key, event.ctrlKey, event.shiftKey)
})
onDestroy(() => {
unsub()
unsub2()
unsub3()
})
</script>
<script>
import { keyboard } from 'sveltui'
// Built-in: Tab and Shift+Tab cycle focus automatically
// Programmatic control
keyboard.focusNext()
keyboard.focusPrevious()
keyboard.clearFocus()
</script>
ArrowUp, ArrowDown, ArrowLeft, ArrowRightHome, End, PageUp, PageDownEnter, Escape, Tab, Shift+Tab, Backspace, DeleteCtrl+A through Ctrl+Z, Ctrl+C (exits app)a, A, 1, !, etc.)import { mount } from 'sveltui'
mount(() => {
// Your app initialization
}, {
fullscreen: true // Use alternate screen buffer (recommended)
})
SvelTUI's architecture is designed for performance and simplicity:
┌─────────────────────────────────────────────────────────┐
│ Your Svelte App │
│ (Components, State, Event Handlers) │
└─────────────────────────┬───────────────────────────────┘
│
┌─────────────────────────▼───────────────────────────────┐
│ Svelte 5 Reactivity │
│ ($state, $derived, $effect) │
└─────────────────────────┬───────────────────────────────┘
│
┌─────────────────────────▼───────────────────────────────┐
│ SvelTUI Engine │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────────┐ │
│ │ Typed Array │ │ Yoga │ │ Differential │ │
│ │ State │ │ Layout │ │ Renderer │ │
│ └─────────────┘ └─────────────┘ └─────────────────┘ │
└─────────────────────────┬───────────────────────────────┘
│
┌─────────────────────────▼───────────────────────────────┐
│ Terminal │
│ (ANSI escape sequences) │
└─────────────────────────────────────────────────────────┘
Reactive-on-demand Rendering: No fixed FPS loop. Updates happen instantly when state changes, and nothing happens when state is stable.
Typed Arrays for State: Component properties stored in typed arrays for cache-friendly access and minimal memory overhead.
Differential Rendering: Only changed cells are written to the terminal. Press a key, and only the affected characters update.
Happy DOM Integration: Svelte needs a DOM to work. We use Happy DOM as a lightweight shim, letting Svelte's reactivity work unchanged.
SvelTUI supports multiple color formats:
<!-- Hex number (recommended for performance) -->
<Text text="Red" color={0xff0000} />
<!-- CSS color names -->
<Text text="Blue" color="blue" />
<!-- Hex string -->
<Text text="Green" color="#00ff00" />
<!-- RGB -->
<Text text="Yellow" color="rgb(255, 255, 0)" />
SvelTUI includes a powerful theming system with semantic colors. Use the variant prop on components to automatically apply theme colors:
<!-- Box variants affect border color -->
<Box variant="primary" border="rounded">
<Text text="Primary box" />
</Box>
<Box variant="success" border="single">
<Text text="Success!" />
</Box>
<!-- Text variants affect text color -->
<Text text="Warning message" variant="warning" />
<Text text="Error occurred" variant="danger" />
<Text text="Information" variant="info" />
<!-- Text also has muted/bright options -->
<Text text="Subtle hint" muted />
<Text text="Important!" bright />
Available variants:
| Variant | Use Case |
|---|---|
primary |
Main actions, focused elements |
secondary |
Secondary actions, less emphasis |
accent |
Highlighted elements, special emphasis |
success |
Positive feedback, confirmations |
warning |
Caution, important notices |
danger |
Errors, destructive actions |
info |
Informational messages |
<script>
import { getTheme } from 'sveltui'
const theme = getTheme()
// Switch to a different theme
theme().setTheme('dracula')
</script>
Available themes: default, dracula, nord, monokai, solarized
<script>
import { getTheme } from 'sveltui'
const theme = getTheme()
// Access theme colors for custom use
const primaryColor = theme().colors.primary
const bgColor = theme().colors.background
</script>
<Text text="Custom styled" color={theme().colors.accent} />
# Clone the repository
git clone https://github.com/RLabs-Inc/sveltui.git
cd sveltui
# Install dependencies
bun install
# Build the framework
bun run build
# Run the demo
bun run demo
Contributions are welcome! Whether it's:
Please feel free to open an issue or submit a pull request.
fullscreen: true. Workaround: use fullscreen mode for apps that need resize support.SvelTUI stands on the shoulders of giants:
MIT License - see LICENSE for details.
Built with Svelte 5 and a lot of terminal escape sequences