toolbar: Add Toolbar and ToolbarGroup components - #3128
Merged
Merged
Conversation
An unstyled container that groups controls and owns the roving-focus contract of an ARIA toolbar: `Role::Toolbar` with orientation, and arrow keys that move focus among focusable descendants, wrapping at the ends. Traversal walks the rendered tab stops constrained to the container subtree, the same approach `Root` uses for focus traps, so it works with any focusable children without their cooperation. The container itself is not a tab stop. A non-wrapping mode would need to tell a wrapped step from an ordinary one, which GPUI's public tab-stop API cannot do, so wrapping is always on. Co-authored-by: GLM (ZCode) <noreply@z.ai>
Follows the status_bar precedent: `toolbar.background` falls back to the title bar background and `toolbar.border` to the title bar border, so existing themes pick up sane values without per-theme edits. Co-authored-by: GLM (ZCode) <noreply@z.ai>
A themed command bar with left/right pinned regions and a middle region whose alignment follows the pinned ends, matching StatusBar's region contract. Sizes via `Sizable` scale bar height, spacing, and text together (28/32/40/48 px). Keyboard roving and toolbar semantics come from `gpui_base::Toolbar`; the styled layer only adds tokens, regions, and sizing. Each instance takes an explicit id, which keeps its focus state stable across frames. Co-authored-by: GLM (ZCode) <noreply@z.ai>
Documents three sections: a document command bar layout, the four sizes (with hosted buttons matching each bar size), and the region alignment cases for the dynamic middle. Co-authored-by: GLM (ZCode) <noreply@z.ai>
Bilingual component page covering regions, sizes, keyboard roving focus, theming, and the API reference, plus entries in both component indexes. Co-authored-by: GLM (ZCode) <noreply@z.ai>
An unstyled container that groups a run of related toolbar items and carries an accessible name, so assistive technology reads them as one unit. The surrounding toolbar's roving arrow-key focus traverses group items like direct children, since containment follows the element tree. Unlike Base UI's Toolbar.Group, the group cannot disable its children: that API propagates through React context into Base UI's own button primitives, which has no equivalent for arbitrary GPUI children, and the a11y layer exposes no disabled state for a container node. Co-authored-by: GLM (ZCode) <noreply@z.ai>
Surface the base group through the styled toolbar module so applications reach it next to Toolbar. Co-authored-by: GLM (ZCode) <noreply@z.ai>
Group the history buttons under an accessible "History" label in the document toolbar example. Co-authored-by: GLM (ZCode) <noreply@z.ai>
Covers grouping with an accessible name, the spacing note, and the boundary that groups cannot disable their children in GPUI. Co-authored-by: GLM (ZCode) <noreply@z.ai>
Co-authored-by: Codex <codex@openai.com>
Co-authored-by: Codex <codex@openai.com>
3 tasks done
madcodelife
pushed a commit
that referenced
this pull request
Sep 25, 2026
#3235) ## Summary Since #3128 every "Rust & WASM" example under `/base/` (motion, button, dialog, …) came up blank on the website, with the console full of `RefCell already borrowed`. The first error is a panic in `TextSystem::resolve_font`: failed to resolve font '.SystemUIFont' or any of the fallbacks: .ZedMono, .ZedSans, Helvetica, ... #3128 switched the examples' root font from `Inter Variable` to `.SystemUIFont` so the native binaries pick up the OS font. `gpui-pre-web` resolves that alias to "IBM Plex Sans" and starts with an empty font database, so the first text layout panicked and the canvas never painted. The bundled Inter no longer matched anything. This is the same failure #2933 fixed for the gallery; that PR left the base examples alone because they still rendered at the time. - `crates/base/examples/showcase/mod.rs`, `crates/base/examples/motion/mod.rs`: bundle the existing IBM Plex Sans subset from `crates/story-web/fonts` instead of Inter for the web build, so the alias resolves. Inter was not referenced by either example anymore; the wasm download shrinks by about 40 KB. - `crates/story-web/scripts/subset-fonts.py`: also scan `crates/base/examples/motion` when subsetting, so text added to that example stays covered. ## How to Test 1. `cd crates/base/examples/wasm && make build`, then `bun run dev` in `website/` and open `/base/motion` and `/base/primitives/button`. 2. Before: the example frame stays blank, the console shows the panic above followed by repeated `RefCell already borrowed`. Reproduced on https://gpui-kit.com/base/motion and `/examples/base?component=button`. 3. After: the motion tabs and the button example render, with zero panics. Verified with headless Chromium (WebGPU) against the local dev server. 4. `rustfmt --check`, `typos` and `cargo clippy -p gpui-base-examples --all-targets -- --deny warnings` are clean. ## Checklist - [x] I have read the [CONTRIBUTING](../CONTRIBUTING.md) document and followed the guidelines. - [x] Reviewed the changes in this PR and confirmed AI generated code (If any) is accurate. - [x] Passed `cargo run` for story tests related to the changes. Written with AI assistance (Claude Code): investigation, fix and verification. Generated with [Claude Code](https://claude.com/claude-code) Co-authored-by: 李波 <bo.li@longbridge-inc.com> Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Description
Adds horizontal
ToolbarandToolbarGroupcomponents for application command rows, with behavior ingpui-baseand density/theme presentation ingpui-component.gpui-baseowns behavior.Toolbarexposes the horizontal toolbar accessibility role and roving Left/Right focus across focusable descendants, including wrapping and disabled navigation.ToolbarGroupadds labeled semantic groups without imposing presentation.gpui-componentowns presentation. The styled Toolbar propagates one density to hosted controls, aligns mixed controls on one center line, and automatically presents hosted Buttons asghost + compactcommands.content(div().flex_1())handle trailing alignment; there are noleftorrightregions.Small, supportsXSmall,Small, andMedium, uses equal padding on every edge, and treatsLargeasMedium.gpui-baseshowcase demonstrates groups, separators, a trailing Search input, keyboard behavior, and visible command feedback. English and Chinese documentation are included.Public API
gpui-baseToolbar::new(id)creates a horizontal toolbar.Toolbar::disabled(value)disables roving keyboard navigation. Hosted controls remain owned by the caller.ToolbarGroup::new(id)creates a semantic subgroup.ToolbarGroup::label(label)supplies its accessible name.gpui-componentToolbar::new(id)creates a transparent, borderless Small toolbar.child/childrenappendSizablecontrols and propagate the final toolbar size.content/contentsappend separators, labels, spacers, and custom content without resizing them.disabled(value)disables Toolbar navigation; callers also disable hosted controls.with_size(size)supportsXSmall,Small, andMedium;Largefalls back toMedium.ToolbarGrouppropagates its inherited size to grouped controls.Buttonvalues automatically receive the compact ghost toolbar presentation.Breaking Changes
None. These components are new in this PR.
Test Plan
cargo fmt --checkgit diff --checkcargo test -p gpui-base toolbar --libcargo test -p gpui-component toolbar::tests --libcargo check -p gpui-component-story -p gpui-component-shellcargo check --manifest-path crates/base/examples/native/Cargo.toml --bin componentsAI Assistance
The implementation and review were completed with agent assistance; commits include the corresponding
Co-authored-bytrailers.