flet-terminal
A native, GPU-accelerated terminal control for Flet, built on top of xterm.dart.
flet-terminal provides high-performance VT100/ANSI terminal emulation across Windows, Linux, macOS, Android, and Web, utilizing low-latency binary DataChannel streaming to render thousands of lines per second without UI freezing.
Fully compatible with Flet 0.86's declarative component model (@ft.component, @ft.observable, use_state, use_effect) — including frozen-control safety via the built-in thaw() context manager.
Download Flet Terminal
Try the standalone Flet Terminal desktop application directly on your OS:
| Platform | Download | Notes |
|---|---|---|
| 🪟 Windows (x64) | FletTerminal_windows_x64.zip | Portable Windows executable (.exe) |
| 🐧 Linux (x86_64) | FletTerminal_linux_x86_64.tar.gz | Universal Linux tarball (tar -xzf) |
| 📦 All Releases | View Releases Page | Changelog and release notes |
Features
- High-Throughput Binary Streaming: Routes terminal data over Flet
DataChanneldirectly to thexterm.dartcanvas, bypassing string/MsgPack serialization overhead. - Cross-Platform Compatibility: Full feature parity across Desktop (
pty/winpty), Mobile (Android), and Web (WASM/Pyodide). - Declarative-First Design: Built for Flet 0.86's React-like component model. All internal mutations use
thaw()to safely update frozen controls inside declarative trees. - Responsive Mobile Wrapper & Zoom Controls:
MobileTerminalincludeszoom_in(),zoom_out(),reset_zoom(), and a customizable virtual accessory keyboard (ESC,TAB,CTRL,ALT, arrows) with sticky modifier toggles and collapsible state. - Reactive CTRL/ALT Modifiers: Sticky modifier buttons are
@ft.componentinstances subscribed to an@ft.observableModifierState— they repaint instantly on toggle, reset, or external state change. - Real Cursor Blink: A Dart-side
Timer.periodictogglescursorVisibleMode+notifyListeners()for true blink (upstream xterm 4.0.0 has no built-in blink). - 4 Built-in Themes:
Dracula,JetBrains Dark,Matrix Green, andColab Light(Material light palette with orange cursor). Settings popup displays accurate checkmarks that update live. - Interactive Search & Selection: Built-in search bar with match counter, scrollback control, and clipboard integration (
select_all,copy_selection,paste,clear_selection). - Frozen-Control Safety: The
thaw()context manager (exported fromflet_terminal.frozen_support) temporarily lifts Flet's_frozenflag so imperative mutations work inside declarative trees — the same pattern Flet uses internally in_before_update_safe.
Installation
Install via pip:
pip install flet-terminal
Or using uv:
uv add flet-terminal
Quickstart
1. Declarative App (Recommended — Flet 0.86)
import flet as ft
from flet_terminal import MobileTerminal, BUILTIN_THEMES
@ft.component
def App():
page = ft.context.page
mt, _ = ft.use_state(lambda: MobileTerminal(
show_extra_keys=True,
show_search=False,
show_settings=True,
scrollback=10000,
font_family="JetBrains Mono",
font_size=13.0,
cursor_blink=True,
theme=BUILTIN_THEMES["JetBrains Dark"],
expand=True,
))
def on_bytes(payload: bytes):
# Echo back or forward to a PTY / remote shell
mt.send_bytes(payload)
ft.use_effect(lambda: mt.set_on_bytes(on_bytes), [])
return ft.Column(controls=[mt], spacing=0, expand=True)
def main(page: ft.Page):
page.title = "My Terminal"
page.theme_mode = ft.ThemeMode.DARK
page.padding = 0
page.render(App)
ft.run(main)
2. Basic Terminal (Terminal)
import flet as ft
from flet_terminal import Terminal, BUILTIN_THEMES
def main(page: ft.Page):
page.theme_mode = ft.ThemeMode.DARK
term = Terminal(
scrollback=10000,
font_family="JetBrains Mono",
font_size=13.0,
cursor_blink=True,
theme=BUILTIN_THEMES["Dracula"],
expand=True,
)
def on_terminal_input(data: bytes):
term.send_bytes(data)
term.set_on_bytes(on_terminal_input)
page.add(term)
term.write("\x1b[1;32mWelcome to FletTerminal!\x1b[0m\r\n> ")
ft.run(main)
3. Imperative Construction Inside Async Tasks
If you build MobileTerminal outside a component render (e.g. inside page.run_task), wrap construction in a throwaway renderer so the internal @ft.component buttons can instantiate:
from flet.components.component import Renderer
with Renderer().with_context():
mt = MobileTerminal(theme=BUILTIN_THEMES["JetBrains Dark"], expand=True)
Reactivity is unaffected — Component.update() creates its own renderer on every re-render.
API Reference
Terminal Properties
| Property | Type | Default | Description |
|---|---|---|---|
scrollback |
int |
10000 |
Maximum number of scrollback lines retained in the ring buffer. |
font_family |
str |
"JetBrains Mono" |
Monospace font family for rendering text. |
font_size |
float |
13.0 |
Font point size. |
cursor_style |
str |
"block" |
Cursor shape. Currently only "block" is supported (underline/bar removed due to upstream xterm 4.0.0 painter bug). |
cursor_blink |
bool |
True |
Whether the terminal cursor blinks (real Dart-side timer). |
theme |
dict |
None |
Dictionary mapping ANSI color keys to hex colors. |
read_only |
bool |
False |
When True, disables user keyboard input into the terminal canvas. |
auto_focus |
bool |
True |
Automatically focuses the terminal when mounted. |
Terminal Methods
| Method | Arguments | Description |
|---|---|---|
send_bytes(payload) |
bytes |
Sends binary data directly over the DataChannel to the terminal canvas. |
write(data) |
str | bytes |
Writes text or escape sequences to the terminal. |
clear() |
— | Clears the terminal scrollback and visible screen buffer. |
focus() |
— | Requests keyboard focus on the terminal control. |
search(query, start, direction) |
str, int, str |
Highlights and selects matching text in the scrollback buffer. |
select_all() |
— | Selects all text currently in the buffer. |
clear_selection() |
— | Clears any active selection. |
paste() |
— | Pastes clipboard content into the terminal. |
Terminal Events
| Event | Handler | Description |
|---|---|---|
on_data |
Callable[[ft.ControlEvent], None] |
Triggered when string-based text input occurs. |
on_resize |
Callable[[ft.ControlEvent], None] |
Fired when dimensions change. Event data contains JSON {"cols": int, "rows": int}. |
on_title_change |
Callable[[ft.ControlEvent], None] |
Triggered when OSC 0/2 title escape sequences are received. |
on_bell |
Callable[[ft.ControlEvent], None] |
Triggered when the bell character (\a / 0x07) is received. |
on_selection_change |
Callable[[ft.ControlEvent], None] |
Fired when selection or search matches update. |
MobileTerminal Additional Methods & Properties
| Method / Property | Description |
|---|---|
set_theme(name) |
Switch to a built-in theme by name. |
set_cursor_style(style) |
Set cursor style (currently "block" only). |
toggle_cursor_blink() |
Toggle cursor blink on/off. |
zoom_in(step=1.0) |
Increase font size. |
zoom_out(step=1.0) |
Decrease font size. |
reset_zoom() |
Reset to default font size. |
toggle_search() |
Show/hide the built-in search bar. |
copy_selection() |
Copy selected text to clipboard. |
paste() |
Paste clipboard into terminal. |
select_all() / clear_selection() |
Selection helpers. |
send_bytes(payload) / write(data) / clear() / focus() |
Inherited from Terminal. |
set_on_bytes(handler) |
Register the input handler. |
| Read-only properties | |
font_size |
Current font size. |
cursor_blink |
Current blink state. |
cursor_style |
Current cursor style. |
theme_name |
Active theme name (or None). |
show_search |
Whether search bar is visible (settable). |
ctrl_active / alt_active |
Sticky modifier state (settable). |
ExtraKeysBar Constructor
| Parameter | Type | Default | Description |
|---|---|---|---|
on_send_payload |
Callable[[bytes], None] |
required | Called with the final byte payload after modifier processing. |
on_modifier_change |
Callable[[bool, bool], None] |
required | Called with (ctrl, alt) when sticky state changes. |
show_settings |
bool |
True |
Show the gear icon settings popup. |
on_set_theme |
Callable[[str], None] |
None |
Theme preset callback. |
on_set_cursor |
Callable[[str], None] |
None |
Cursor style callback. |
on_toggle_blink |
Callable[[], None] |
None |
Blink toggle callback. |
on_toggle_search |
Callable[[], None] |
None |
Search toggle callback. |
on_copy / on_paste / on_select_all / on_clear |
Callable[[], None] |
None |
Clipboard/buffer callbacks. |
keys |
list[tuple[str, bytes | None]] |
DEFAULT_EXTRA_KEYS |
Custom key layout. None payload = modifier key. |
Built-in Themes
from flet_terminal import BUILTIN_THEMES, get_theme
# Available: "Dracula", "JetBrains Dark", "Matrix Green", "Colab Light"
my_theme = get_theme("Dracula")
| Theme | Background | Cursor | Best for |
|---|---|---|---|
| Dracula | #1E1F29 |
#FF79C6 (pink) |
Dark mode default |
| JetBrains Dark | #1E1E2E |
#F5E0DC (warm white) |
Dark mode (Catppuccin-inspired) |
| Matrix Green | #0D1117 |
#00FF66 (green) |
Retro / hacker aesthetic |
| Colab Light | #FFFFFF |
#F97316 (orange) |
Light mode / follows app theme |
Frozen-Control Support
Flet 0.86's declarative renderer stamps _frozen = True on all component-rendered controls. Imperative mutations (.update(), property assignment) raise RuntimeError: Frozen controls cannot be updated.
flet_terminal handles this internally via thaw():
from flet_terminal.frozen_support import thaw
with thaw(some_control):
some_control.style = new_style
some_control.update()
All MobileTerminal setters (set_theme, zoom_in, toggle_search, etc.) and ExtraKeysBar mutations already use thaw() internally — no extra wrapping needed by consumers.
License
This project is licensed under the MIT License. See LICENSE for details.
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file flet_terminal-0.3.7.tar.gz.
File metadata
- Download URL: flet_terminal-0.3.7.tar.gz
- Upload date:
- Size: 29.5 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
1447351190ed96c246309fbfe0d224f181085fc209009f223c31194e1ae7eb97
|
|
| MD5 |
ffd789a4280a0ed8ce09caa8f155c200
|
|
| BLAKE2b-256 |
0306c6ac48243374a610e9c0386257c3299d201466cf9230c0adc9722d1b92cf
|
Provenance
The following attestation bundles were made for flet_terminal-0.3.7.tar.gz:
Publisher:
publish.yml on Nwokike/flet-terminal
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
flet_terminal-0.3.7.tar.gz -
Subject digest:
1447351190ed96c246309fbfe0d224f181085fc209009f223c31194e1ae7eb97 - Sigstore transparency entry: 2553757982
- Sigstore integration time:
-
Permalink:
Nwokike/flet-terminal@25a8db3f1efe3c65611545d55ed9721071ac9c57 -
Branch / Tag:
refs/heads/main - Owner: https://github.com/Nwokike
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@25a8db3f1efe3c65611545d55ed9721071ac9c57 -
Trigger Event:
workflow_dispatch
-
Statement type:
File details
Details for the file flet_terminal-0.3.7-py3-none-any.whl.
File metadata
- Download URL: flet_terminal-0.3.7-py3-none-any.whl
- Upload date:
- Size: 30.2 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
9200d12fcb72474dd205e1e3a8d38428fa311e41ef6132f30d28e2d6428f7c5e
|
|
| MD5 |
3f334727c365e09fdeb2a341206e086e
|
|
| BLAKE2b-256 |
f66a018ddbea1edb80291c1a0c9bb63addbebadef63c1b8987b61e80323d950f
|
Provenance
The following attestation bundles were made for flet_terminal-0.3.7-py3-none-any.whl:
Publisher:
publish.yml on Nwokike/flet-terminal
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
flet_terminal-0.3.7-py3-none-any.whl -
Subject digest:
9200d12fcb72474dd205e1e3a8d38428fa311e41ef6132f30d28e2d6428f7c5e - Sigstore transparency entry: 2553758031
- Sigstore integration time:
-
Permalink:
Nwokike/flet-terminal@25a8db3f1efe3c65611545d55ed9721071ac9c57 -
Branch / Tag:
refs/heads/main - Owner: https://github.com/Nwokike
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@25a8db3f1efe3c65611545d55ed9721071ac9c57 -
Trigger Event:
workflow_dispatch
-
Statement type: