research/gpui-kit.md
GPUI Kit
Use this file to choose the kit layer for each piece of the app, read the theme model before c132 builds the token bridge, see how a kit app starts and how its headless tests look, and know what breaks between the weekly releases. Facts come from gpui-kit.com, the repo and crates.io; every source was read on 2026-11-09. Companion: gpui.md for the engine, platform.md for what the kit leaves to us.
Identity
- "A production-ready Rust UI framework with 75+ components and primitives, WebAssembly, accessibility, UI integration testing, data tables, docking, charts, code editing, and JavaScript extensions." By Longbridge; author Jason Lee (huacnlee), with 115 PRs merged into Zed itself. — https://gpui-kit.com, https://zed.dev/blog/community-champion-jason-lee
- The repo began as
gpui-componenton 2024-06-13 and became GPUI Kit with v0.6.0 on 2026-09-03: "GPUI Component remains the styled component layer within the toolkit." — https://api.github.com/repos/longbridge/gpui-kit/releases/tags/v0.6.0 - Current version 0.9.1, published 2026-11-09, "a backward-compatible patch release". Cadence since September 2026: one release a week, a minor about every three weeks, in step with the weekly
gpui-presnapshot of Zed. — https://gpui-kit.com/releases, https://crates.io/api/v1/crates/gpui-kit - Licence Apache-2.0; docs also CC BY 4.0. 20,096 stars, 233 contributors. — https://github.com/longbridge/gpui-kit
- Production use: Longbridge Pro, a trading desktop "shipped on all three platforms", replaced an Electron client. Fifteen other apps are listed (Zedis, tty7, BarSQL, SwitchHosts Lite, GeeTree…). — https://gpui-kit.com/apps
- Platforms: macOS, Windows, Linux "Stable: Used by production desktop applications"; wasm "Showcase only"; mobile experimental. — https://gpui-kit.com/docs
The layers
The site says three Kit layers; its own docs page lists five, counting the engine and the facade. — https://gpui-kit.com/docs, https://gpui-kit.com/base
| Crate | What it is | Use it when |
|---|---|---|
gpui (via gpui-pre) | The engine (gpui.md) | Always, through the facade |
gpui-kit | The facade: re-exports GPUI and "brings together Base, Component, and default assets through one dependency". Paths gpui_kit::*, ::base, ::component, ::assets, ::platform. | Always; it is the one dependency an app declares |
gpui-base | "Unstyled behavior, controlled state, focus, overlays, virtual lists, dock infrastructure, and semantic design tokens." Button::new("save") "has no default height, padding, background, border, or radius". | "You are building a design system and want to own every visual choice." Not V1 (D5) |
gpui-component | The styled library: 80 component pages, themes, data tables, dock, editor. Builds on gpui-base; "Applications can use either layer directly." | "You want a complete set of styled, ready-to-use desktop components." Our layer (D2). |
gpui-shell | JavaScript extensions on QuickJS, "one granted capability at a time". "It is not an Electron or a Tauri. There is no WebView, no DOM, no HTML or CSS." At "Milestone M0… not a stable interface". | Later, if notices or trainings should arrive as scripts without a new binary (c133, c137) |
Rule from the architecture doc: gpui-base "must not import gpui-component themes, assets, or façade types"; the arrow runs application → component → base → GPUI. — https://raw.githubusercontent.com/longbridge/gpui-kit/main/docs/ARCHITECTURE.md
Published crates, all 0.9.1: gpui-kit, gpui-base, gpui-component, gpui-component-macros, gpui-kit-assets (Lucide icons), gpui-fps, gpui-shell, gpui-webview. Features on gpui-kit: default = ["component", "assets"], gpui-fast, test-support, inspector, profiler, speech, syntect, tree-sitter and one tree-sitter-<lang> per grammar. — https://raw.githubusercontent.com/longbridge/gpui-kit/main/crates/kit/Cargo.toml
Components our pages need
| Need (page) | Kit piece | Notes |
|---|---|---|
| Inventory lists, Events log | DataTable: "Virtual scrolling, fixed and resizable columns, sorting, and cell selection across hundreds of thousands of rows"; a TableDelegate supplies columns, counts and cells; columns pin left or right; rows and columns virtualise; sorting the data is the delegate's job | The old stateful Table became DataTable in 0.6.0; Table is now a declarative element. — https://gpui-kit.com/component/data-table |
| Long lists | VirtualList: "Render only the visible range, including differently sized items." | |
| Status cards, Config panes | Sidebar, Tabs, GroupBox, DescriptionList, Form, Input, Select, Switch, Badge, Tag, Alert, Empty, Skeleton, Progress | Empty and Skeleton cover R5's honest states |
| Status resources | Charts: Line, Bar, Area, Pie, Radar, Candlestick, Sankey; appear animation on by default since 0.7.1 (.appear(false)) | — https://gpui-kit.com/component/chart |
| Events detail | TextView (selectable Markdown and HTML, no CSS layout), Tree (for a JSON tree), Editor (rope, Tree-sitter or syntect) | The Editor is heavy; a read-only TextView may do |
| Dialogs, toasts | Root "always mounts the dialog, sheet and notification layers above application content"; window.open_dialog, window.open_sheet, window.push_notification; Notification::info(...).system() routes to the OS | — https://gpui-kit.com/component/root, https://gpui-kit.com/docs/system-notification |
| Window chrome | TitleBar with a menu bar; TitleBar::window_options() as the base WindowOptions; native traffic lights on macOS, drawn controls on Linux | — https://gpui-kit.com/component/title-bar |
| Workspace layouts | Dock: tab groups, nested splits, collapsible docks; DockLayout "is a value… serialize it, compare it"; "the layout foundation used by Longbridge in production" | Probably not V1 |
| qmap embed (D8) | gpui-webview, experimental, X11 only on Linux | Costed in comparison.md |
Chat surfaces (Message, Bubble, Attachment, Speech) and a Command palette exist too; the full list is 80 component pages and 40 primitive pages. — https://gpui-kit.com/llms-full.txt
Theming
This is the part a designer needs, and the ground for c132's token bridge.
- Access.
cx.theme()through theActiveThemetrait:cx.theme().primary,.background,.foreground. The coding guide forbids raw colours in app code: "read a semantic color fromcx.theme()or add the missing role to the product theme". — https://gpui-kit.com/component/theme, https://gpui-kit.com/docs/coding-guides - Two vocabularies. The component
ThemeColorhas 134 roles:background, foreground, border, input, ring, selection, muted(+foreground), accent(+foreground), primary(+hover/active/foreground), secondary(+…), danger(+…), success(+…), warning(+…), info(+…), link(+hover/active), popover, sidebar(+foreground/border/accent/primary), title_bar, status_bar, scrollbar, list(+active/even/head/hover), table(+active/even/head/foot/hover/row_border), tab(+active/bar/foreground), chart_bullish, chart_bearish, chart_grid, button(+primary/secondary/danger/info/success/warning, each with hover/active/foreground), plus a base palettered, green, blue, yellow, magenta, cyanwith_lightvariants. The word isdanger, notdestructive. Beneath it,gpui-basecarries an 18-colour shadcn-shapedColorTokensset (background, foreground, surface, primary, secondary, muted, accent, destructive, border, input, ring, selection, each with a foreground) and scales forradius {none sm md lg xl full},spacing {xxs…xxl},typography {sans, mono, xs…xl},shadow {sm md lg}. "PreferTheme::semantic_tokens()for new application-owned presentation". — https://raw.githubusercontent.com/longbridge/gpui-kit/main/crates/component/src/theme/theme_color.rs, https://raw.githubusercontent.com/longbridge/gpui-kit/main/crates/base/src/theme_tokens.rs - A theme is a JSON file, validated by
.theme-schema.json: aThemeSet(name, author, url, themes[]), eachThemeConfigwithname, mode, is_default, font.size, font.family, mono_font.family, radius, radius.lg, window.radius, shadow, colors, highlight. Colour keys are dotted roles ("primary.background","primary.hover.background","sidebar.accent.foreground","table.row.border","chart.1"); values take hex, Tailwind palette names ("neutral-200/60") and gradients on tokens that opt in. The default theme is shadcn's neutral palette with 99 keys. — https://raw.githubusercontent.com/longbridge/gpui-kit/main/.theme-schema.json, https://raw.githubusercontent.com/longbridge/gpui-kit/main/crates/component/src/theme/default-theme.json - Built in: 21 theme files (ayu, catppuccin, gruvbox, solarized, tokyonight, macos-classic…), "38 (36 variants + Light/Dark)" presets. — https://api.github.com/repos/longbridge/gpui-kit/contents/themes
- Loading and switching:
ThemeRegistry::watch_dir("./themes", cx, …), thenTheme::update(cx, |t| t.apply_config(&config));Theme::change(ThemeMode::Dark, None, cx)"refreshes every window";Theme::sync_system_appearance(window, cx)follows the OS when the app wiresobserve_window_appearanceto it.gpui_component::initstarts in Light. Since 0.9.0 the theme structs are#[non_exhaustive]: start fromDefault::default(). — https://gpui-kit.com/component/theme, https://gpui-kit.com/releases - Zoom is the base font.
Rootcallswindow.set_rem_size(cx.theme().font_size), sotheme.font_size = px(18.)scales everything built with rem helpers. Radius: a finite scale, inner radius ≈ outer minus the gap; density tiers with Medium as default. — https://gpui-kit.com/docs/design-guides - Fonts: theme
font_family/mono_font_family; "Use the platform UI font for interface text and monospace only for code"; bundle a font withinclude_bytes!+add_fonts, then name it in the theme. Licensing in platform.md. — https://gpui-kit.com/docs/fonts
A first sketch of the bridge, for c132 to test (not a ruling):
Qpoint token (brand/design_tokens.md) | Kit role |
|---|---|
Grape 500 #895AE8, 600 hover, 700 active | primary, primary.hover, primary.active; ring; link |
Leaf 300 #58E392 | success (never danger or warning) |
| Grey 900 / 600 text, Grey 50/100 surfaces, Grey 200/300 borders | foreground / muted.foreground, background / sidebar / list.even, border / table.row.border |
error #EF4444, warning #F59E0B, info #D7CAFE | danger, warning, info |
| Inter / Geist Mono | font.family / mono_font.family, if shipped (c131 Q5) |
The app skeleton
use gpui_kit::*;
fn main() {
application().with_assets(assets::Assets).run(|cx| {
init(cx); // themes and the enabled layers; before any window
open_window(WindowOptions::default(), cx, // cx.open_window plus the Root wrapper
|_, cx| cx.new(|_| HelloWorld)).expect("Failed to open window");
});
}
"Root owns the window's overlay layers, including dialogs, sheets and notifications. Return your content view from the closure, not another Root." Quit and close actions are the app's to define. On Linux with a WebView, start with gpui_kit::platform::linux(WindowingModes::X11). — https://gpui-kit.com/docs/getting-started, https://gpui-kit.com/component/root
The repo's crates/story is the gallery (cargo run opens it; cargo run -p gpui-component-story -- NotificationStory opens one story), with 86 stories; examples/ holds 30 runnable apps (hello_world, dock, editor, markdown, webview, system_monitor…). Our stories crate (c131 R6) follows this shape. — https://api.github.com/repos/longbridge/gpui-kit/contents/crates/story/src/stories
Headless UI tests
"A UI integration test renders real components or an application view in a headless window, simulates clicks, keyboard input and scrolling, then verifies state, focus, layout and application callbacks." Enabled by the test-support feature; "no additional testing crate, GPUI fork or Cargo patch". — https://gpui-kit.com/docs/test
#[gpui_kit::test]
fn saves_a_profile_through_the_ui(cx: &mut TestAppContext) {
// … open the window …
window.render_frame(cx);
window.click("name", cx);
window.input("Ada", cx);
window.click("save", cx);
assert_eq!(window.find("status").label(), Some("Saved: Ada"));
assert_eq!(profile.read(cx).submitted.as_deref(), Some("Ada"));
}
- API:
find(id),find_all,within(id),click,right_click,double_click,hover,scroll,drag,press("backspace"),input,render_frame; snapshots giverole(),bounds(),visible(),focused(),disabled(),label()(the accessibility name, not visible text),value(),checked(). - Limits: no general rendered-text assertion ("The pinned GPUI version does not expose an enumeration of anonymous rendered text"); no positive enabled assertion.
- CI: the kit runs its suite on
ubuntu-latest,macos-latestandwindows-latestwith no Xvfb orDISPLAY; only the opt-in pixel suite needs a Vulkan driver. — https://raw.githubusercontent.com/longbridge/gpui-kit/main/.github/workflows/ci.yml
For us: this is "the demo is the test" in Rust. One story per page state, asserted by role and label, is both the design site and the regression suite (c131 R6, c132 medium B).
AccessKit
- Claim: "AccessKit roles, names, states, relationships, and actions are built into the interaction layer and covered by tests." Per component: Button and Link (role, name, activation), Checkbox / Switch / Toggle / Radio (checked state), Input (role by content type, value,
SetValue; masked values withheld), Select (ComboBox), Tabs, Slider and Progress (numeric range), Table ("row, header and cell roles with indices"), DataTable grid role since 0.9.0. Icon-only buttons need.accessibility_label("…"). — https://gpui-kit.com/docs/accessibility - Limits the kit states: "A passing headless tree assertion cannot prove what a screen reader announces or whether a focus ring is visible"; "Check assistive technology separately on each target platform." It rates itself Partial. No screen-reader run is reported anywhere; four GPUI accessibility bugs were filed on 2026-11-08 and 09 by a library user. — https://gpui-kit.com/docs/comparison, https://github.com/zed-industries/zed/issues/66691
wasm builds
- "WebAssembly support is used primarily to showcase and try components in a browser… shipping an application in a browser is not a supported path yet." Label: Showcase only. — https://gpui-kit.com/docs/webassembly
- Toolchain:
wasm32-unknown-unknown+wasm-bindgen; the gallery pins nightly (CI:nightly-2026-10-31).gpui_webbuilds on stable only with itsmultithreadedfeature off; whether a kit app does is unverified. Backend: WebGPU, then WebGL2. One canvas, one window; dialogs render inside it; fonts must be embedded (no font database on the web); accessibility is painted into a canvas. - The gallery at https://gpui-kit.com/gallery/ takes
?story=and a theme JSON; every Base primitive page embeds a live wasm example "backed by the same example crate that can run natively". Build:cd crates/story-web && make dev. - For c132 medium C: embedding a mock screen in a lab page is exactly the kit's own showcase use, and the theme JSON can be passed in. Fidelity of text input and tables in wasm, and the nightly toolchain, are the costs to measure.
Version churn
The kit does not use crates.io gpui or a Zed git rev. It pins Longbridge's weekly gpui-pre snapshot exactly (=0.3.12 today; "a caret requirement let the weekly release move applications onto a newer snapshot that gpui-component did not compile with"), and CI fails on a non-exact pin. Never pin a gpui-pre-* crate yourself. gpui-fast is an optional feature that "switches GPUI, native platforms, the WebAssembly backend, and every enabled Kit layer together". — https://raw.githubusercontent.com/longbridge/gpui-kit/main/Cargo.toml, https://gpui-kit.com/docs/installation
| Release | Date | What broke |
|---|---|---|
| 0.6.0 | 2026-09-03 | The rename; gpui-kit facade, gpui-base, gpui-shell; Table → DataTable; dock split into base and styled halves; Dialog::new(cx); many fields made private |
| 0.6.1 | 09-09 | Headless UI tests arrive |
| 0.7.0 | 09-28 | Root moved to Base; gpui_kit::open_window replaces manual Root; window.open_dialog; Plot renames; versioned docs begin |
| 0.7.3 | 10-12 | Optional GPUI Fast backend; gpui-pre =0.3.9 |
| 0.8.0 | 10-19 | gpui-wry → gpui-webview; Linux WebView must start on X11; scroll behaviour changes; TestWindowExt gains required methods |
| 0.8.1 | 10-26 | Upstream breaks passed through: KeyBinding::new needs static strings, Modifiers::secondary() needs &App, PlatformInput::Scroll |
| 0.9.0 | 11-02 | Theme structs #[non_exhaustive]; Window::text_system() returns &Rc<…>; animations read the executor clock |
| 0.9.1 | 11-09 | None; gpui-pre =0.3.12, gpui-fast 0.1.14, a rustls-webpki CVE fix |
Every release note has a "Breaking changes" section with migration snippets; docs are versioned (/versions/v0.9.0, /versions/main) and pages carry maturity labels (Stable, Preview, Experimental, Showcase only). — https://gpui-kit.com/releases
For c131: pin gpui-kit = "=0.9.1", move on a schedule, version-stamp PATTERNS.md with the kit release, and expect a migration hour per minor.
Platform notes and gaps
- Requirements: macOS 15 or later plus Xcode Command Line Tools; Windows 10 or later, MSVC toolchain, CMake; Linux verified on Ubuntu 24.04 with Vulkan drivers, Wayland or X11, fontconfig, xkbcommon,
libwebkit2gtk-4.1; Rust 1.92 or later. — https://gpui-kit.com/docs/installation - Not in the kit: a tray or status item (no occurrence of "tray" in the docs; none in GPUI either); auto-update ("Your application and its distribution system own the update policy"; a guide shows
self_update); installers ("cargo build --releaseproduces an executable, not an installer"). Notifications exist through GPUI but on macOS need a real.appbundle and on Linux a D-Bus notification daemon. All of these are platform.md's subject. — https://gpui-kit.com/docs/auto-update, https://gpui-kit.com/docs/packaging, https://gpui-kit.com/docs/system-notification - Hello World release binary: "~12 MB" by the kit's own estimate. — https://gpui-kit.com/docs/comparison
- Linux: client-side decorations, a GPUI-drawn menu fallback, WebView on X11 only.
Open questions
- Does any kit app follow the OS light/dark appearance by default, or must every app wire
observe_window_appearance? The code suggests the latter. - Does a kit app build for wasm on stable with
single_threaded_web()? - What does Longbridge Pro ship with: upstream GPUI or GPUI Fast?
- Is the "~12 MB" hello binary right for 0.9.1 on each OS? The spike measures.
Sources
https://gpui-kit.com · https://gpui-kit.com/docs (getting-started, installation, test, accessibility, webassembly, coding-guides, design-guides, fonts, comparison, webview, auto-update, packaging, system-notification, native-extension) · https://gpui-kit.com/component (root, theme, title-bar, data-table, dock, chart, editor) · https://gpui-kit.com/base · https://gpui-kit.com/shell · https://gpui-kit.com/releases · https://gpui-kit.com/apps · https://gpui-kit.com/gallery/ · https://gpui-kit.com/llms-full.txt · https://github.com/longbridge/gpui-kit (Cargo.toml, crates/kit/Cargo.toml, docs/ARCHITECTURE.md, .theme-schema.json, crates/component/src/theme/*, crates/base/src/theme_tokens.rs, .github/workflows/ci.yml, themes/) · https://api.github.com/repos/longbridge/gpui-kit/releases · https://crates.io/api/v1/crates/gpui-kit · https://crates.io/api/v1/crates/gpui-pre · https://zed.dev/blog/community-champion-jason-lee · https://github.com/zed-industries/zed/issues/66691