Button
The Button element with multiple variants, sizes, and states. Supports icons, loading states, and can be grouped together.
Import
use gpui_kit::component::{
Sizable as _,
button::{Button, ButtonGroup, ButtonVariants as _},
};Usage
The marked recipe below is a complete, Tested consumer recipe. The remaining examples are contextual fragments; keep the imports above when using variant or size builders.
<!-- recipe:command-control:start -->use gpui_kit::IntoElement;
use gpui_kit::component::{
Sizable as _,
button::{Button, ButtonVariants as _},
};
pub fn primary_command() -> impl IntoElement {
Button::new("save").primary().small().label("Save changes")
}<!-- recipe:command-control:end -->Basic Button
Button::new("my-button")
.label("Click me")
.on_click(|_, _, _| {
println!("Button clicked!");
})Variants
use gpui_kit::component::button::ButtonVariants as _;
// Primary button
Button::new("btn-primary").primary().label("Primary")
// Secondary button (default)
Button::new("btn-secondary").label("Secondary")
// Danger button
Button::new("btn-danger").danger().label("Delete")
// Warning button
Button::new("btn-warning").warning().label("Warning")
// Success button
Button::new("btn-success").success().label("Success")
// Info button
Button::new("btn-info").info().label("Info")
// Ghost button
Button::new("btn-ghost").ghost().label("Ghost")
// Link button
Button::new("btn-link").link().label("Link")
// Text button
Button::new("btn-text").text().label("Text")Outline Buttons
Outline style is not a variant itself, but can be combined with other variants.
use gpui_kit::component::button::ButtonVariants as _;
Button::new("btn").primary().outline().label("Primary Outline")
Button::new("btn").danger().outline().label("Danger Outline")Compact Button
The compact method reduces the padding of the button for a more condensed appearance.
// Compact (reduced padding)
Button::new("btn")
.label("Compact")
.compact()Sizeable
The Button supports the Sizable trait for different sizes.
use gpui_kit::component::Sizable as _;
Button::new("btn").xsmall().label("Extra Small")
Button::new("btn").small().label("Small")
Button::new("btn").label("Medium") // default
Button::new("btn").large().label("Large")With Icons
The icon method supports multiple types, allowing you to use different visual indicators:
- Icon / IconName - Static icons for actions and visual cues
- Spinner - Animated loading indicator for async operations
- ProgressCircle - Circular progress indicator showing completion percentage
All icon types automatically adapt to the button's size and can be customized with colors and other properties.
Icon Types
use gpui_kit::component::{Icon, IconName};
// Using IconName (simplest)
Button::new("btn")
.icon(IconName::Check)
.label("Confirm")
// Using Icon with custom size
Button::new("btn")
.icon(Icon::new(IconName::Heart))
.label("Like")
// Icon only (no label)
Button::new("btn")
.icon(IconName::Search)Spinner Icon
Use a Spinner to indicate loading or processing state:
use gpui_kit::component::{ActiveTheme as _, spinner::Spinner};
// Basic spinner
Button::new("btn")
.icon(Spinner::new())
.label("Loading...")
// Spinner with custom color
Button::new("btn")
.icon(Spinner::new().color(cx.theme().blue))
.label("Processing")
// Spinner with icon
Button::new("btn")
.icon(Spinner::new().icon(IconName::LoaderCircle))
.label("Syncing")ProgressCircle Icon
Use a ProgressCircle to show progress percentage:
use gpui_kit::component::{
ActiveTheme as _, Sizable as _,
button::ButtonVariants as _,
progress::ProgressCircle,
};
// Basic progress circle
Button::new("btn")
.icon(ProgressCircle::new("install-progress").value(45.0))
.label("Installing...")
// Progress circle with custom color
Button::new("btn")
.primary()
.icon(
ProgressCircle::new("download-progress")
.value(75.0)
.color(cx.theme().primary_foreground)
)
.label("Downloading")
// Different sizes
Button::new("btn")
.small()
.icon(ProgressCircle::new("progress-1").value(60.0))
.label("Installing...")
Button::new("btn")
.large()
.icon(ProgressCircle::new("progress-2").value(80.0))
.label("Installing...")Dynamic Icon Updates
Icons can be updated dynamically based on component state:
struct InstallButton {
progress: f32,
is_installing: bool,
}
impl InstallButton {
fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
let button = Button::new("install-btn")
.label(if self.is_installing {
"Installing..."
} else {
"Install"
});
if self.is_installing {
button.icon(
ProgressCircle::new("install-progress")
.value(self.progress)
)
} else {
button.icon(IconName::Download)
}
}
}Loading State with Icons
When a button is in loading state, it automatically handles icon transitions:
// If icon is already a Spinner or ProgressCircle, it will be shown during loading
Button::new("btn")
.icon(Spinner::new())
.label("Processing")
.loading(true) // Spinner will continue to show
// If icon is a regular Icon, it will be replaced with a Spinner during loading
Button::new("btn")
.icon(IconName::Save)
.label("Saving")
.loading(true) // Icon will be replaced with SpinnerWith a dropdown caret icon
The .dropdown_caret method can allows adding a dropdown caret icon to end of the button.
Button::new("btn")
.label("Options")
.dropdown_caret(true)Button States
There have disabled, loading, selected state for buttons to indicate different statuses.
use gpui_kit::component::{Disableable as _, Selectable as _};
// Disabled
Button::new("btn")
.label("Disabled")
.disabled(true)
// Loading
Button::new("btn")
.label("Loading")
.loading(true)
// Selected
Button::new("btn")
.label("Selected")
.selected(true)Button Group
ButtonGroup::new("btn-group")
.child(Button::new("btn1").label("One"))
.child(Button::new("btn2").label("Two"))
.child(Button::new("btn3").label("Three"))Toggle Button Group
use gpui_kit::component::Selectable as _;
ButtonGroup::new("toggle-group")
.multiple(true) // Allow multiple selections
.child(Button::new("btn1").label("Option 1").selected(true))
.child(Button::new("btn2").label("Option 2"))
.child(Button::new("btn3").label("Option 3"))
.on_click(|selected_indices, _, _| {
println!("Selected: {:?}", selected_indices);
})Custom Variant
use gpui_kit::component::{
ActiveTheme as _, Colorize as _,
button::{ButtonCustomVariant, ButtonVariants as _},
};
let custom = ButtonCustomVariant::new(cx)
.color(cx.theme().magenta)
.foreground(cx.theme().primary_foreground)
.hover(cx.theme().magenta.opacity(0.1))
.active(cx.theme().magenta);
Button::new("custom-btn")
.custom(custom)
.label("Custom Button")API Reference
Examples
With Tooltip
Button::new("btn")
.label("Hover me")
.tooltip("This is a helpful tooltip")
.tooltip_placement(Placement::Bottom)Use .tooltip_placement(...) to prefer a side for either .tooltip(...) or
.tooltip_with_action(...). The tooltip still flips when that side does not fit.
Omit placement to keep automatic positioning.
Custom Children
Button::new("btn")
.child(
h_flex()
.items_center()
.gap_2()
.child("Custom Content")
.child(IconName::ChevronDown)
.child(IconName::Eye)
)Documentation license: original prose and illustrations for which GPUI Kit holds licensing rights are also offered under CC BY 4.0. When copying or adapting, credit GPUI Kit, link the source (https://gpui-kit.com/component/button) and https://creativecommons.org/licenses/by/4.0/, and indicate changes. Code examples and software source use Apache-2.0; third-party material retains its terms; existing Apache-2.0 permissions remain.
Bundled from GPUI Kit. Documentation prose: CC BY 4.0; code examples: Apache-2.0. Changes: documentation links localized, asset URLs made absolute, and this attribution added.