Color Swatch Picker
Choose from a predefined set of colors.
use herogpui::components::color_picker::ColorSwatchPicker;ColorSwatchPicker on docs.rsSource at v0.14.0
Usage
Showing Usage, live: HeroGPUI compiled to WebAssembly. The canvas has no accessibility tree; each example's description and code below carry the same information.
Runs in a view's render: self is the view holding this example's state and cx is its Context<Self>.
use herogpui::prelude::{ActiveTheme, ColorSwatchPicker, PickerColor, SizeXl};
use herogpui::gpui::prelude::*;
use herogpui::gpui::{App, px};
use herogpui::gpui;
let selected = self.swatch_selected;
gpui::div()
.flex()
.flex_col()
.items_start()
.justify_center()
.gap(px(12.))
.children(vec![
ColorSwatchPicker::new("color-swatch-picker-main", palette())
.value(selected)
.size(SizeXl::Lg)
.on_change(cx.listener(|this, c: &PickerColor, _, cx| {
this.swatch_selected = *c;
cx.notify();
}))
.into_any_element(),
para(&format!("Selected: {}", selected.to_hex()), cx),
])Runs in a view's render: self is the view holding this example's state and cx is its Context<Self>.
use herogpui::prelude::{ColorSwatchPicker, PickerColor, SwatchShape};
use herogpui::gpui::prelude::*;
use herogpui::gpui::px;
use herogpui::gpui;
let selected = self.swatch_selected;
gpui::div()
.flex()
.flex_col()
.items_start()
.justify_center()
.gap(px(12.))
.children(vec![
ColorSwatchPicker::new("color-swatch-picker-circle", palette())
.value(selected)
.on_change(cx.listener(
|this, c: &PickerColor, _, cx| {
this.swatch_selected = *c;
cx.notify();
},
))
.into_any_element(),
ColorSwatchPicker::new("color-swatch-picker-sq", palette())
.value(selected)
.on_change(cx.listener(
|this, c: &PickerColor, _, cx| {
this.swatch_selected = *c;
cx.notify();
},
))
.shape(SwatchShape::Square)
.into_any_element(),
])Also calls palette (included when you copy).
Runs in a view's render: self is the view holding this example's state and cx is its Context<Self>.
use herogpui::prelude::{ColorSwatchPicker, PickerColor, SizeXl};
use herogpui::gpui::prelude::*;
use herogpui::gpui::px;
use herogpui::gpui;
let selected = self.swatch_selected;
gpui::div()
.flex()
.flex_col()
.items_start()
.justify_center()
.gap(px(12.))
.children(SizeXl::ALL
.iter()
.map(|sz| {
ColorSwatchPicker::new(format!("color-swatch-picker-{sz:?}"), palette())
.value(selected)
.on_change(cx.listener(
|this, c: &PickerColor, _, cx| {
this.swatch_selected = *c;
cx.notify();
},
))
.size(*sz)
}))Also calls palette (included when you copy).
Runs in a view's render: self is the view holding this example's state and cx is its Context<Self>.
use herogpui::prelude::{ColorSwatchPicker, PickerColor};
use herogpui::gpui::prelude::*;
use herogpui::gpui::px;
use herogpui::gpui;
let selected = self.swatch_selected;
gpui::div()
.flex()
.flex_col()
.items_start()
.justify_center()
.gap(px(12.))
.children(vec![ColorSwatchPicker::new("color-swatch-picker-disabled", palette())
.value(selected)
.is_disabled(true)
.into_any_element()])Also calls palette (included when you copy).
`ColorSwatchPicker.Item.isDisabled` dims one swatch — unclickable and out of the tab order — while the rest stay pickable: the difference from the whole-picker `isDisabled` above. Runs in a view's render: self is the view holding this example's state and cx is its Context<Self>.
use herogpui::prelude::{ColorSwatchPicker, PickerColor};
use herogpui::gpui::prelude::*;
use herogpui::gpui::px;
use herogpui::gpui;
let selected = self.swatch_selected;
gpui::div()
.flex()
.flex_col()
.items_start()
.justify_center()
.gap(px(12.))
.children(vec![
ColorSwatchPicker::new("color-swatch-picker-disabled-item", palette())
.value(selected)
.disabled_keys([2])
.on_change(cx.listener(|this, c: &PickerColor, _, cx| {
this.swatch_selected = *c;
cx.notify();
}))
.into_any_element(),
])Also calls palette (included when you copy).
Runs in a view's render: self is the view holding this example's state and cx is its Context<Self>.
use herogpui::prelude::{ColorSwatchPicker, PickerColor, SwatchLayout};
use herogpui::gpui::prelude::*;
use herogpui::gpui::px;
use herogpui::gpui;
let selected = self.swatch_selected;
gpui::div()
.flex()
.flex_col()
.items_start()
.justify_center()
.gap(px(12.))
.children(vec![ColorSwatchPicker::new("color-swatch-picker-stack", palette())
.value(selected)
.on_change(cx.listener(|this, c: &PickerColor, _, cx| {
this.swatch_selected = *c;
cx.notify();
}))
.layout(SwatchLayout::Stack)
.into_any_element()])Also calls palette (included when you copy).
An element expression with window: &mut Window and cx: &mut App in scope.
use herogpui::prelude::{ColorSwatchPicker, PickerColor};
use herogpui::gpui::prelude::*;
use herogpui::gpui::px;
use herogpui::gpui;
gpui::div()
.flex()
.flex_col()
.items_start()
.justify_center()
.gap(px(12.))
.children(vec![ColorSwatchPicker::new("color-swatch-picker-default", palette())
.default_value(palette()[2])
.into_any_element()])Also calls palette (included when you copy).
Runs in a view's render: self is the view holding this example's state and cx is its Context<Self>.
use herogpui::prelude::{ActiveTheme, ColorSwatchPicker, PickerColor};
use herogpui::gpui::prelude::*;
use herogpui::gpui::{App, px};
use herogpui::gpui;
let selected = self.swatch_selected;
gpui::div()
.flex()
.flex_col()
.items_start()
.justify_center()
.gap(px(12.))
.children(vec![
ColorSwatchPicker::new("color-swatch-picker-controlled", palette())
.value(selected)
.on_change(cx.listener(|this, c: &PickerColor, _, cx| {
this.swatch_selected = *c;
cx.notify();
}))
.into_any_element(),
para(&format!("Selected: {}", selected.to_hex()), cx),
])`indicator` replaces the built-in selected checkmark. The square picker below uses a heart. Runs in a view's render: self is the view holding this example's state and cx is its Context<Self>.
use herogpui::prelude::{ColorSwatchPicker, PickerColor, SizeXl, SwatchShape, icons};
use herogpui::gpui::prelude::*;
use herogpui::gpui::px;
use herogpui::gpui;
let selected = self.swatch_selected;
gpui::div()
.flex()
.flex_col()
.items_start()
.justify_center()
.gap(px(12.))
.children(vec![
ColorSwatchPicker::new("color-swatch-picker-indicator", palette())
.value(selected)
.on_change(cx.listener(|this, c: &PickerColor, _, cx| {
this.swatch_selected = *c;
cx.notify();
}))
.shape(SwatchShape::Square)
.size(SizeXl::Lg)
.indicator(|_, _| {
gpui::svg()
.size(px(12.))
.path(icons::HEART_FILL)
.text_color(gpui::white())
.into_any_element()
})
.into_any_element(),
])Also calls palette (included when you copy).
`item_content` receives each item's color plus selected, hovered, pressed, focused, focus-visible, and disabled state. These custom tiles use that state while the picker keeps navigation and selection. Runs in a view's render: self is the view holding this example's state and cx is its Context<Self>.
use herogpui::prelude::{ColorSwatchPicker, PickerColor, SizeXl, icons};
use herogpui::gpui::prelude::*;
use herogpui::gpui::px;
use herogpui::gpui;
let selected = self.swatch_selected;
gpui::div()
.flex()
.flex_col()
.items_start()
.justify_center()
.gap(px(12.))
.children(vec![
ColorSwatchPicker::new("color-swatch-picker-item-content", palette())
.value(selected)
.size(SizeXl::Xl)
.on_change(cx.listener(|this, c: &PickerColor, _, cx| {
this.swatch_selected = *c;
cx.notify();
}))
.item_content(|_, state| {
gpui::div()
.size_full()
.rounded(px(8.))
.bg(state.color.to_hsla())
.when(state.is_pressed, |tile| tile.opacity(0.65))
.when(state.is_selected, |tile| {
tile.child(
gpui::svg()
.size(px(12.))
.path(icons::HEART_FILL)
.text_color(gpui::white()),
)
})
.into_any_element()
})
.into_any_element(),
])Also calls palette (included when you copy).
Runs in a view's render: self is the view holding this example's state and cx is its Context<Self>.
use herogpui::prelude::{ColorSwatchPicker, PickerColor, SwatchLayout, SwatchShape};
let selected = self.swatch_selected;
ColorSwatchPicker::new("color-swatch-picker-square", palette())
.value(selected)
.shape(SwatchShape::Square)
.layout(SwatchLayout::Stack)
.on_change(cx.listener(|this, c: &PickerColor, _, cx| {
this.swatch_selected = *c;
cx.notify();
}))Also calls palette (included when you copy).
Helpers used by these examples
Plain functions over the public API, defined once here and copied with each example that calls them.
/// The demo palette used by the color pages.
fn palette() -> Vec<PickerColor> {
[
"#0085F5", "#17C964", "#F5A524", "#F31260", "#7828C8", "#0E8AAA", "#71717A", "#18181B",
]
.into_iter()
.filter_map(PickerColor::from_hex)
.collect()
}fn para(text: &str, cx: &App) -> gpui::AnyElement {
let colors = cx.colors();
gpui::div()
.text_size(px(14.5))
.line_height(px(24.))
.text_color(colors.foreground)
.max_w(px(720.))
.child(text.to_owned())
.into_any_element()
}Anatomy
Rust types
Color Swatch Picker is assembled from these builders. The API reference lists each one.
Customization
Shared appearance belongs on ThemeBuilder::components and .recipe("name"). Typed builders change how Color Swatch Picker looks at one call site. Every builder also carries sx for placement, width and flex: it takes GPUI's own styling methods and refines them over the component's root after the theme, so an instance override wins. Behaviour builders live in the API reference below.
Styling
| Method | Values | Description |
|---|---|---|
size(SizeXl) | xs | sm | md | lg | xl | Drives item edge, border, radius, indicator, hit geometry, wrapping, and grid navigation stride. |
shape(SwatchShape) | circle | square | Selects the per-size item and swatch radii. |
// The one slot for caller-owned low-level styling: GPUI's
// styling methods, refined over the root element last.
.sx(|el| {
el.bg(gpui::rgba(0xffa500ff)) // background
.text_color(gpui::rgba(0x000000ff)) // text
.w(gpui::px(13.)) // size
.h(gpui::px(12.))
})API reference
Against HeroUI v3.2.6: 20 entries ported, 3 partial, 3 not ported. Partial rows are marked in the tables; entries not ported are listed under each table with the reason.
Builders
| Builder | Values | Default | Description |
|---|---|---|---|
value( | string | | — | Controlled selection changes only when the owner supplies the reported color. |
default_value( | string | | — | Seeds picker-owned selection once. |
on_change( | Fn( | — | Reports pointer and keyboard selection changes. |
size( | xs | | SizeXl:: | Drives item edge, border, radius, indicator, hit geometry, wrapping, and grid navigation stride. |
shape( | circle | | SwatchShape:: | Selects the per-size item and swatch radii. |
layout( | grid | | SwatchLayout:: | Grid wraps and uses geometric row navigation; stack is vertical and uses Up/Down. |
new(Partial | AnyElement | — | The Rust constructor receives a concrete palette and composes one item per color. |
new( | string | | required | Each palette color is supplied by index and reaches item render state. |
disabled_keys( | true | | false | Per-index disabled items dim, leave navigation, and mask interaction state. |
item_content( | AnyElement | | Swatch + Indicator | Replacement content receives color, hover, press, selection, focus, focus-visible, and disabled state. |
indicator( | AnyElement | | checkmark | Replacement indicator content receives the complete item state. |
Not ported3 HeroUI entries not ported
| HeroUI v3 | Why it is not ported |
|---|---|
ColorSwatchPicker.className | Browser classes are unavailable. |
ColorSwatchPicker.render | The GPUI root element cannot be replaced. |
ColorSwatchPicker.Item.className | Browser classes are unavailable. |
Parts
| Part | Description |
|---|---|
ColorSwatchPicker | Selection owner and wrapping grid or vertical stack. |
ColorSwatchPicker | Stable focus, pointer, selection, and render-state owner. |
ColorSwatchPicker | Checkerboard-backed color visual with selected and hover geometry. |
ColorSwatchPicker | Centered selected marker with luminance-aware default color or caller content. |
States
| State | Builder | Description |
|---|---|---|
Hovered | interaction | Enabled unselected swatches grow to 1.1 and item content receives hover. |
Pressed | interaction | Enabled item content receives live pointer and keyboard press state. |
Selected | resolved value | The color border is revealed by a 0.77 inner swatch and item/indicator state updates. |
Focused | cursor | Exactly one enabled item owns the roving focus handle. |
Focus visible | with_focus_ring | Keyboard-origin focus draws the shared ring and reaches item state. |
Disabled | is_disabled | Whole-picker and per-item disabling dim, suppress events, remove navigation stops, and mask state. |