Icon Group
An icon toolbar preset.
Try it
Interact with the control below. This preview runs the exact code sample shown on this page.
Basic use
use xgpui_luma_look_radix as radix;
use gpui::{Context, IntoElement, Styled};
use xgpui_luma::controls::control_group::{ControlGroupItem, ControlGroupItemLike};
struct Example {
control: xgpui_luma::controls::control_group::ControlGroup<xgpui_luma::controls::control_group::ControlGroupItem>,
selected_tools: Vec<gpui::SharedString>,
}
impl Example {
fn new(cx: &mut Context<Self>) -> Self {
let look = cx.try_global::<radix::Look>().cloned().unwrap_or_else(radix::Look::built_in);
let control = radix::icon_group_builder::<ControlGroupItem>(&look, "tools", xgpui_luma::theme::ControlSize::Md)
.items([
ControlGroupItem::new("select").label("Select"),
ControlGroupItem::new("move").label("Move"),
ControlGroupItem::new("zoom").label("Zoom"),
])
.item_template(std::sync::Arc::new(|model, _, _| {
let icon = match model.item.id().as_ref() {
"move" => "assets/lucide/move.svg",
"zoom" => "assets/lucide/zoom-in.svg",
_ => "assets/lucide/mouse-pointer.svg",
};
gpui::svg().path(icon).size(gpui::px(16.0))
.text_color(model.foreground.unwrap_or_else(gpui::transparent_black)).into_any_element()
}))
.on_value_changed(cx, |app, _, _, selected_ids, cx| {
app.selected_tools = selected_ids.clone();
cx.notify();
})
.spawn(cx);
Self { control, selected_tools: Vec::new() }
}
}Integration snippet, checked against the current SDK and Radix crates. cx is the initialized owner context. The control retains its callbacks; callback owners are held weakly. Render self.control.clone() in the owner’s view.
Radix styling
icon_group_builder(&look, id, size) returns the SDK horizontal toolbar preset with Radix shell and square icon-item styling. Supply glyphs through the SDK item-content template; selection, callbacks, and focus remain in Control Group.
Pass an explicit Look, including forks. Theme adapters retain that binding; notify affected controls and their owners after palette, mode, or stylesheet edits. Resolved look values are snapshots and must be resolved again during render.
See the Radix control support table for adapter and utility status.
SDK behavior & customization
Aliases and presets over Control Group; it does not introduce a second group engine.
Relevant contracts: IconGroupEvent.
Events
Callbacks follow the existing SDK event stream. Registrations append, hold the owner weakly, and live until the control is released. cx.notify() requests an owner redraw. Compound payloads are borrowed; scalar values are passed by value.
| Event / payload | Callback |
|---|---|
Activate { activated_id: SharedString } | .on_activate(cx, |app, activated_id, cx| { … }) |
Change { changed_id: SharedString, selected: bool, selected_ids: Vec<SharedString> } | .on_value_changed(cx, |app, changed_id, selected, selected_ids, cx| { … }) |
ItemBoundsChanged { item_id: SharedString, bounds: Bounds<Pixels> } | .on_item_bounds_changed(cx, |app, item_id, bounds, cx| { … }) |
FocusChanged { focused: bool } | .on_focus_changed(cx, |app, focused, cx| { … }) |
ItemFocused { item_id: SharedString } | .on_item_focused(cx, |app, item_id, cx| { … }) |
Use .on_event(cx, |app, event, cx| { … }) for all events. Factory-created controls support the same callbacks through ControlGroupEventExt. Existing cx.subscribe observers remain supported.