Documentación
Design system
The component vocabulary TDE apps are built from.
En esta página
TDE-CN
TDE UI is the design system every TDE-owned app and every tde-app-sdk app is
built from. It takes the composition discipline of Ratatui and the coherent
component vocabulary of shadcn/ui, and adapts both to a terminal — without
turning the terminal into a bitmap surface.
It is shared vocabulary, not a web port. A Dialog here is a cell-based,
rect-bound, immediate-mode surface that happens to answer to the same name.
The executable source of truth is the TDE UI Demo:
tde ui-demoThe Demo is not a marketing gallery. It is the canonical inventory: every component appears exactly once, each page is smoke-rendered in every built-in theme at both a desktop 120 × 40 and a Web Share phone 30 × 24, and both sizes have readable textual goldens.
The six pillars
1. Semantic, theme-native styling
Components consume Theme, Tokens, TextRole, StatusKind and named icons.
Apps never invent RGB values, spacing scales or private border conventions.
Default always follows the active system theme, and all sixteen built-in palettes
— from the default Tonal Slate through Editorial Paper, platform-inspired
palettes and familiar editor themes — satisfy one semantic contract. See
Themes.
2. Constraint-based composition
Geometry is computed before painting. Layout, LayoutConstraint, Flex,
RectExt, PageContainer and the typed scaffolds return rectangles, and the
same rectangles are shared by rendering and hit-testing. Components clip to the
Rect they receive, including tiny and degenerate Web Share viewports.
3. A uniform widget contract
Reusable controls implement Widget or StatefulWidget. Configuration belongs
to the widget; mutable selection and editing state belongs to the caller. In
practice, every component:
- renders into an explicit
Rect; - exposes typed mouse and key outcomes, not app-specific side effects;
- takes time and data by injection, and reads no global I/O during render;
- measures what it paints and paints what it measured;
- keeps rendering and hit-testing on one layout calculation.
4. Mouse-first, keyboard-complete
Every visible action has a mouse target first, and the same action must be
reachable without a memorized shortcut: arrows move focus or selection,
Enter / Space activate, Esc closes or returns, Tab may assist form
traversal. Single-letter shortcuts are accelerators, never the only route.
Hidden in-place value cyclers are prohibited — use Select, SelectField,
Toggle, Checkbox or SegmentedControl so the choice is visible.
5. One adaptive component model
The desktop and Web Share use the same components and the same state. At compact
width the layout becomes Android-like: AppBar, NavDrawer, stacked content and
touch-sized targets replace a permanently visible rail. The supported minimum
catalog viewport is 30 × 24 cells, with no fake overflow. There is no second
mobile component set.
6. Hybrid cells plus pixel-tier decoration
Cells stay canonical — for text, focus, input, SSH and fallback terminals.
Components may additionally emit resolution-independent Decor intents for
rounded corners, inset chips, hairlines and shadows. Kitty, Ghostty and Web Share
render those intents at device resolution; every other host keeps the complete
cell rendering. See Terminal graphics.
Text is never rasterized into decoration, apps never branch on the host, and no app draws private pixel chrome.
The catalog
Eight groups. Each component has exactly one canonical page in the Demo.
| Group | Components |
|---|---|
| Foundations | Theme, Tokens, Breakpoint, TextRole, Icon, Kbd, PaintCtx, Widget/StatefulWidget, Chrome, FocusScope, Elevation/Decor |
| Inputs | Button, Toggle, CheckboxGroup, RadioGroup, SegmentedControl, TextInput, TextArea, Field, Form, Select, SelectField, ColorPicker |
| Navigation | AppBar, Breadcrumb, TabBar, SubTabs, Toolbar, Menu, NavDrawer, Scrollbar |
| Data Display | List, Tree, DataTable, KeyValueTable, FileTree, FilePicker, FileBrowser, MarkdownBlock, QrCodePanel |
| Data Viz | Gauge, Sparkline, BarChart, LineChart, AreaChart, Timeline, MetricCard |
| Feedback | Banner, StatusPill, Badge, Spinner, Skeleton, EmptyState, Toast, ToastStack |
| Overlays | Dialog, Popover, Popup, SelectModal, ShortcutCaptureModal |
| Layouts | Layout/Constraints/Flex, Card, Divider, PageContainer, AppShell, FormPage, MasterDetail, SidebarShell, SplitPane, StatusBar |
DataTable is canonical over Table: its named column ids and typed activation
and sort outcomes are the stable app-author contract. Floating surfaces share one
elevation contract — their cell fallback is opaque and legible, and their pixel
tier adds the matching corners, hairline and shadow.
Compatibility aliases
These names still work so existing apps keep compiling, but they do not get their own catalog page:
| Old name | Canonical |
|---|---|
Panel | Card |
TextBox | TextInput |
Progress | Gauge |
Table | DataTable |
SharedChrome | Chrome |
Specialized renderers
Some content is deliberately not a generic widget: the terminal emulator, the code editor and its syntax and diff views, the spreadsheet grid, the browser and media surface, image and ANSI-art previews, and domain visualizers. They still obey the theme, the clipping, the chrome, the overlays and the keyboard rules — only their core pixels are custom.
The PaintCtx rule
Paint only through a component, or through a bounded
PaintCtx. Never straight to theCanvas.
A raw Canvas knows one thing: the physical screen edge. It does not know about
your window, a nested pane, a modal, or a 30-column Web Share viewport. A direct
write is therefore a write that can escape any of them.
When no component models the surface you need — a per-character-styled diff row,
a syntax-highlighted buffer, procedural art — the answer is a widget that takes
PaintCtx, never a raw Canvas. That keeps the surface bounded by its own
rect and inside the pixel-tier and Web Share paths.
Exemptions exist, but each one must be written down. A raw write survives only where the cell is a protocol payload rather than ink — the kitty placeholder cell encodes a 24-bit image id in its foreground and the raster row and column in its background, and the compositor inverts or blits already-composed cells, which no painting helper can express. Every such site carries a comment explaining the constraint; the gate rejects any that does not.
Interaction rules
- Compute layout once and share its rectangles with paint and hit-test paths.
- Paint only through a component or a bounded
PaintCtx. - Use
PageContainerfor standard page gutters and typed scaffolds for common screen shapes. - Reserve
DataTablefor app-facing tabular data; useKeyValueTablefor editable key/value records. - Keep actions visible and consistently ordered. Destructive actions use the semantic danger role.
- Preserve the same task on desktop and compact layouts — change presentation, not capability.
- Emit
Decoronly as progressive enhancement over a complete cell rendering. - Every mouse handler needs a visible keyboard path through focus plus
Enter/Space.
Related
- Your first app — the SDK, the manifest and the harness.
- Themes — the semantic palette these components consume.
- Terminal graphics — which hosts render the pixel tier.
- Web Share — the compact presentation the same components produce.