gpui-style-guide
π―Skillfrom longbridge/gpui-component
Enforces consistent GPUI component design patterns by providing a comprehensive style guide for creating and reviewing Rust UI components.
Installation
npx skills add https://github.com/longbridge/gpui-component --skill gpui-style-guideSkill Details
GPUI Component project style guide based on gpui-component code patterns. Use when writing new components, reviewing code, or ensuring consistency with existing gpui-component implementations. Covers component structure, trait implementations, naming conventions, and API patterns observed in the actual codebase.
Overview
Code style guide derived from gpui-component implementation patterns.
Based on: Analysis of Button, Checkbox, Input, Select, and other components in crates/ui
Component Structure
Basic Component Pattern
```rust
use gpui::{
div, prelude::FluentBuilder as _, AnyElement, App, Div, ElementId,
InteractiveElement, IntoElement, ParentElement, RenderOnce,
StatefulInteractiveElement, StyleRefinement, Styled, Window,
};
#[derive(IntoElement)]
pub struct MyComponent {
id: ElementId,
base: Div,
style: StyleRefinement,
// Configuration fields
size: Size,
disabled: bool,
selected: bool,
// Content fields
label: Option
children: Vec
// Callbacks (use Rc for Clone)
on_click: Option
}
impl MyComponent {
pub fn new(id: impl Into
Self {
id: id.into(),
base: div(),
style: StyleRefinement::default(),
size: Size::default(),
disabled: false,
selected: false,
label: None,
children: Vec::new(),
on_click: None,
}
}
// Builder methods
pub fn label(mut self, label: impl Into
self.label = Some(label.into());
self
}
pub fn on_click(mut self, handler: impl Fn(&ClickEvent, &mut Window, &mut App) + 'static) -> Self {
self.on_click = Some(Rc::new(handler));
self
}
}
impl InteractiveElement for MyComponent {
fn interactivity(&mut self) -> &mut gpui::Interactivity {
self.base.interactivity()
}
}
impl StatefulInteractiveElement for MyComponent {}
impl Styled for MyComponent {
fn style(&mut self) -> &mut StyleRefinement {
&mut self.style
}
}
impl RenderOnce for MyComponent {
fn render(self, window: &mut Window, cx: &mut App) -> impl IntoElement {
// Implementation
self.base
}
}
```
Stateful Component Pattern
```rust
#[derive(IntoElement)]
pub struct Select {
state: Entity
style: StyleRefinement,
size: Size,
// ...
}
pub struct SelectState {
open: bool,
selected_index: Option
// ...
}
impl Select {
pub fn new(state: &Entity
Self {
state: state.clone(),
size: Size::default(),
style: StyleRefinement::default(),
}
}
}
```
Trait Implementations
Sizable
```rust
impl Sizable for MyComponent {
fn with_size(mut self, size: impl Into
self.size = size.into();
self
}
}
```
Selectable
```rust
impl Selectable for MyComponent {
fn selected(mut self, selected: bool) -> Self {
self.selected = selected;
self
}
fn is_selected(&self) -> bool {
self.selected
}
}
```
Disableable
```rust
impl Disableable for MyComponent {
fn disabled(mut self, disabled: bool) -> Self {
self.disabled = disabled;
self
}
fn is_disabled(&self) -> bool {
self.disabled
}
}
```
Variant Patterns
Enum Variants
```rust
#[derive(Clone, Copy, PartialEq, Eq, Default, Debug)]
pub enum ButtonVariant {
Primary,
#[default]
Secondary,
Danger,
Success,
Warning,
Ghost,
Link,
}
```
Trait-Based Variant API
```rust
pub trait ButtonVariants: Sized {
fn with_variant(self, variant: ButtonVariant) -> Self;
/// With the primary style for the Button.
fn primary(self) -> Self {
self.with_variant(ButtonVariant::Primary)
}
/// With the danger style for the Button.
fn danger(self) -> Self {
self.with_variant(ButtonVariant::Danger)
}
// ... more variants
}
```
Custom Variant Pattern
```rust
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
pub struct ButtonCustomVariant {
color: Hsla,
foreground: Hsla,
border: Hsla,
hover: Hsla,
active: Hsla,
shadow: bool,
}
impl ButtonCustomVariant {
pub fn new(cx: &App) -> Self {
Self {
color: cx.theme().transparent,
foreground: cx.theme().foreground,
// ...
shadow: false,
}
}
pub fn color(mut self, color: Hsla) -> Self {
self.color = color;
self
}
// ... more builder methods
}
```
Action and Keybinding Patterns
Context Constant
```rust
const CONTEXT: &str = "Select";
```
Init Function
```rust
pub(crate) fn init(cx: &mut App) {
cx.bind_keys([
KeyBinding::new("up", SelectUp, Some(CONTEXT)),
KeyBinding::new("down", SelectDown, Some(CONTEXT)),
KeyBinding::new("enter", Confirm { secondary: false }, Some(CONTEXT)),
KeyBinding::new("escape", Cancel, Some(CONTEXT)),
])
}
```
Action Usage
```rust
use crate::actions::{Cancel, Confirm, SelectDown, SelectUp};
div()
.key_context(CONTEXT)
.on_action(cx.listener(Self::on_action_select_up))
.on_action(cx.listener(Self::on_action_confirm))
```
Trait Definitions
Item Traits
```rust
pub trait SelectItem: Clone {
type Value: Clone;
fn title(&self) -> SharedString;
fn display_title(&self) -> Option
None
}
fn render(&self, _: &mut Window, _: &mut App) -> impl IntoElement {
self.title().into_element()
}
fn value(&self) -> &Self::Value;
fn matches(&self, query: &str) -> bool {
self.title().to_lowercase().contains(&query.to_lowercase())
}
}
```
Implement for Common Types
```rust
impl SelectItem for String {
type Value = Self;
fn title(&self) -> SharedString {
SharedString::from(self.to_string())
}
fn value(&self) -> &Self::Value {
&self
}
}
impl SelectItem for SharedString { / ... / }
impl SelectItem for &'static str { / ... / }
```
Icon Pattern
IconNamed Trait
```rust
pub trait IconNamed {
fn path(self) -> SharedString;
}
impl
fn from(value: T) -> Self {
Icon::build(value)
}
}
```
IconName Enum
```rust
#[derive(IntoElement, Clone)]
pub enum IconName {
ArrowDown,
ArrowUp,
Check,
Close,
// ... all icon names
}
```
Documentation Patterns
Component Documentation
```rust
/// A Checkbox element.
#[derive(IntoElement)]
pub struct Checkbox { }
```
Method Documentation
```rust
impl Checkbox {
/// Create a new Checkbox with the given id.
pub fn new(id: impl Into
/// Set the label for the checkbox.
pub fn label(mut self, label: impl Into
/// Set the click handler for the checkbox.
///
/// The &bool parameter indicates the new checked state after the click.
pub fn on_click(mut self, handler: impl Fn(&bool, &mut Window, &mut App) + 'static) -> Self { }
}
```
Import Organization Pattern
```rust
// 1. External crate imports
use std::rc::Rc;
// 2. Crate imports
use crate::{
ActiveTheme, Disableable, FocusableExt, Icon, IconName,
Selectable, Sizable, Size, StyledExt,
};
// 3. GPUI imports
use gpui::{
div, prelude::FluentBuilder as _, px, relative, rems,
AnyElement, App, Div, ElementId, InteractiveElement,
IntoElement, ParentElement, RenderOnce,
StatefulInteractiveElement, StyleRefinement, Styled, Window,
};
```
Field Organization
```rust
pub struct Component {
// 1. Identity
id: ElementId,
base: Div,
style: StyleRefinement,
// 2. Configuration
size: Size,
disabled: bool,
selected: bool,
tab_stop: bool,
tab_index: isize,
// 3. Content/children
label: Option
children: Vec
prefix: Option
suffix: Option
// 4. Callbacks (last)
on_click: Option
}
```
Common Patterns
Optional Elements
```rust
pub fn prefix(mut self, prefix: impl IntoElement) -> Self {
self.prefix = Some(prefix.into_any_element());
self
}
```
Callback Patterns
```rust
// Pattern 1: Event parameter first
pub fn on_click(mut self, handler: impl Fn(&ClickEvent, &mut Window, &mut App) + 'static) -> Self {
self.on_click = Some(Rc::new(handler));
self
}
// Pattern 2: State parameter
pub fn on_change(mut self, handler: impl Fn(&bool, &mut Window, &mut App) + 'static) -> Self {
self.on_change = Some(Rc::new(handler));
self
}
```
Static Handler Functions
```rust
fn handle_click(
on_click: &Option
checked: bool,
window: &mut Window,
cx: &mut App,
) {
let new_checked = !checked;
if let Some(f) = on_click {
(f)(&new_checked, window, cx);
}
}
```
Boolean Methods
```rust
// Enable/disable patterns
pub fn cleanable(mut self, cleanable: bool) -> Self {
self.cleanable = cleanable;
self
}
// Toggle methods (no parameter)
pub fn mask_toggle(mut self) -> Self {
self.mask_toggle = true;
self
}
```
Size Methods
Size Trait
```rust
impl Sizable for Component {
fn with_size(mut self, size: impl Into
self.size = size.into();
self
}
}
```
Convenience Size Methods (from StyleSized trait)
Components get .xsmall(), .small(), .medium(), .large() automatically via StyleSized trait.
Rendering Patterns
RenderOnce Pattern
```rust
impl RenderOnce for MyComponent {
fn render(self, window: &mut Window, cx: &mut App) -> impl IntoElement {
let (width, height) = self.size.input_size();
self.base
.id(self.id)
.flex()
.items_center()
.gap(px(8.))
.min_w(width)
.h(height)
.when(self.disabled, |this| {
this.opacity(0.5).cursor_not_allowed()
})
.children(self.children)
}
}
```
Theme Usage
```rust
// Access theme colors
cx.theme().surface
cx.theme().foreground
cx.theme().border
cx.theme().primary
cx.theme().transparent
// Use in components
div()
.bg(cx.theme().surface)
.text_color(cx.theme().foreground)
.border_color(cx.theme().border)
```
Reference Documentation
- Component Examples: See [component-examples.md](references/component-examples.md)
- Full component implementations
- Common patterns in action
- Trait Patterns: See [trait-patterns.md](references/trait-patterns.md)
- Detailed trait implementation guides
- Custom trait design patterns
Quick Checklist
When creating a new component in crates/ui:
- [ ]
#[derive(IntoElement)]on struct - [ ] Include
id: ElementId,base: Div,style: StyleRefinement - [ ] Implement
InteractiveElement,StatefulInteractiveElement,Styled - [ ] Implement
RenderOncetrait - [ ] Implement
Sizableif component has sizes - [ ] Implement
Selectableif component can be selected - [ ] Implement
Disableableif component can be disabled - [ ] Use
Rcfor callbacks - [ ] Use
Optionfor optional child elements - [ ] Import
prelude::FluentBuilder as _ - [ ] Use theme colors via
cx.theme() - [ ] Follow field organization pattern
More from this repository10
Enables asynchronous operations and background tasks in GPUI, allowing seamless coordination between UI updates and concurrent computations.
Defines and manages keyboard-driven actions and key bindings for declarative UI interactions in GPUI applications.
Enables type-safe event handling, subscriptions, and observations for coordinating component interactions in GPUI applications.
Provides CSS-like layout and styling for Rust GPUI components using type-safe, chainable methods for flexbox, sizing, colors, and spacing.
Manages application state through safe, concurrent entities with read, update, and weak reference capabilities for reactive and async-friendly state handling in GPUI.
Enables keyboard-driven focus management and navigation between focusable elements in GPUI user interfaces.
gpui-context skill from longbridge/gpui-component
Enables comprehensive testing of GPUI applications with deterministic, single-threaded test execution for UI components and async operations.
Enables low-level, performance-critical custom UI element creation with precise control over layout, painting, and interaction phases in GPUI.
Manages global application state and configuration in GPUI, enabling centralized data access and sharing across components.