ColorPicker
A versatile color picker component that provides an intuitive interface for color selection. Features include color palettes, hex input, featured colors, and support for various color formats including RGB, HSL, and hex values with alpha channel support.
Import
use gpui_component::color_picker::{ColorPicker, ColorPickerState, ColorPickerEvent};
Usage
Basic Color Picker
use gpui::{Entity, Window, Context};
// Create color picker state
let color_picker = cx.new(|cx|
ColorPickerState::new(window, cx)
.default_value(cx.theme().primary)
);
// Create the color picker component
ColorPicker::new(&color_picker)
With Event Handling
use gpui::{Subscription, Entity};
let color_picker = cx.new(|cx| ColorPickerState::new(window, cx));
let _subscription = cx.subscribe(&color_picker, |this, _, ev, _| match ev {
ColorPickerEvent::Change(color) => {
if let Some(color) = color {
println!("Selected color: {}", color.to_hex());
// Handle color change
}
}
});
ColorPicker::new(&color_picker)
Setting Default Color
use gpui::Hsla;
let color_picker = cx.new(|cx|
ColorPickerState::new(window, cx)
.default_value(cx.theme().blue) // Set default color
);
Different Sizes
// Small color picker
ColorPicker::new(&color_picker).small()
// Medium color picker (default)
ColorPicker::new(&color_picker)
// Large color picker
ColorPicker::new(&color_picker).large()
// Extra small color picker
ColorPicker::new(&color_picker).xsmall()
With Custom Featured Colors
use gpui::Hsla;
let featured_colors = vec![
cx.theme().red,
cx.theme().green,
cx.theme().blue,
cx.theme().yellow,
// Add your custom colors
];
ColorPicker::new(&color_picker)
.featured_colors(featured_colors)
With Icon Instead of Color Square
use gpui_component::IconName;
ColorPicker::new(&color_picker)
.icon(IconName::Palette)
With Label
ColorPicker::new(&color_picker)
.label("Background Color")
Custom Anchor Position
use gpui::Corner;
ColorPicker::new(&color_picker)
.anchor(Corner::TopRight) // Dropdown opens to top-right
Color Selection Interface
Color Palettes
The color picker includes predefined color palettes organized by color family:
- Stone: Neutral grays and stone colors
- Red: Red color variations from light to dark
- Orange: Orange color variations
- Yellow: Yellow color variations
- Green: Green color variations
- Cyan: Cyan color variations
- Blue: Blue color variations
- Purple: Purple color variations
- Pink: Pink color variations
Each palette provides multiple shades and tints of the base color, allowing for precise color selection.
Featured Colors Section
A customizable section at the top of the picker that displays frequently used or brand colors. If not specified, defaults to theme colors:
- Primary colors from the current theme
- Light variants of theme colors
- Essential UI colors (red, blue, green, yellow, cyan, magenta)
Hex Input Field
A text input field that allows direct entry of hex color values:
- Supports standard 6-digit hex format (#RRGGBB)
- Real-time validation and preview
- Updates color picker state automatically
- Press Enter to confirm selection
Color Formats
RGB (Red, Green, Blue)
Colors are internally represented using GPUI's Hsla
format but can be converted to RGB:
let color = cx.theme().blue;
// Access RGB components through Hsla methods
HSL (Hue, Saturation, Lightness)
Native format used by the color picker:
use gpui::Hsla;
// Create HSL color
let color = Hsla::hsl(240.0, 100.0, 50.0); // Blue color
// Access components
let hue = color.h;
let saturation = color.s;
let lightness = color.l;
Hex Format
Standard web hex format with # prefix:
// Convert color to hex
let hex_string = color.to_hex(); // Returns "#3366FF"
// Parse hex string to color
if let Ok(color) = Hsla::parse_hex("#3366FF") {
// Use parsed color
}
Alpha Channel
Full alpha channel support for transparency:
use gpui::hsla;
// Create color with alpha
let semi_transparent = hsla(0.5, 0.8, 0.6, 0.7); // 70% opacity
// Modify existing color opacity
let transparent_blue = cx.theme().blue.opacity(0.5);
The color picker preserves alpha values when selecting colors and allows modification through the alpha component of HSLA colors.
API Reference
ColorPickerState
Method | Description |
---|---|
new(window, cx) | Create a new color picker state |
default_value(color) | Set the default selected color |
set_value(color, window, cx) | Programmatically set the current color |
value() | Get the currently selected color |
ColorPicker
Method | Description |
---|---|
new(state) | Create a new color picker with the given state |
featured_colors(colors) | Set custom featured colors array |
size(size) | Set the picker size (XSmall, Small, Medium, Large) |
icon(icon) | Display icon instead of color square |
label(text) | Add a label to the color picker |
anchor(corner) | Set dropdown anchor position |
ColorPickerEvent
Event | Description |
---|---|
Change(Option<Hsla>) | Emitted when color selection changes |
Size Options
Size | Description |
---|---|
Size::XSmall | Extra small picker button |
Size::Small | Small picker button |
Size::Medium | Medium picker button (default) |
Size::Large | Large picker button |
Anchor Positions
Corner | Description |
---|---|
Corner::TopLeft | Dropdown opens below and to the right |
Corner::TopRight | Dropdown opens below and to the left |
Corner::BottomLeft | Dropdown opens above and to the right |
Corner::BottomRight | Dropdown opens above and to the left |
Examples
Color Theme Editor
struct ThemeEditor {
primary_color: Entity<ColorPickerState>,
secondary_color: Entity<ColorPickerState>,
accent_color: Entity<ColorPickerState>,
}
impl ThemeEditor {
fn new(window: &mut Window, cx: &mut Context<Self>) -> Self {
let primary_color = cx.new(|cx|
ColorPickerState::new(window, cx)
.default_value(cx.theme().primary)
);
let secondary_color = cx.new(|cx|
ColorPickerState::new(window, cx)
.default_value(cx.theme().secondary)
);
let accent_color = cx.new(|cx|
ColorPickerState::new(window, cx)
.default_value(cx.theme().accent)
);
Self {
primary_color,
secondary_color,
accent_color,
}
}
fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
v_flex()
.gap_4()
.child(
h_flex()
.gap_2()
.items_center()
.child("Primary Color:")
.child(ColorPicker::new(&self.primary_color))
)
.child(
h_flex()
.gap_2()
.items_center()
.child("Secondary Color:")
.child(ColorPicker::new(&self.secondary_color))
)
.child(
h_flex()
.gap_2()
.items_center()
.child("Accent Color:")
.child(ColorPicker::new(&self.accent_color))
)
}
}
Brand Color Selector
let brand_colors = vec![
Hsla::parse_hex("#FF6B6B").unwrap(), // Brand Red
Hsla::parse_hex("#4ECDC4").unwrap(), // Brand Teal
Hsla::parse_hex("#45B7D1").unwrap(), // Brand Blue
Hsla::parse_hex("#96CEB4").unwrap(), // Brand Green
Hsla::parse_hex("#FFEAA7").unwrap(), // Brand Yellow
];
ColorPicker::new(&color_picker)
.featured_colors(brand_colors)
.label("Brand Color")
.size(Size::Large)
Toolbar Color Picker
use gpui_component::IconName;
ColorPicker::new(&text_color_picker)
.icon(IconName::Type)
.size(Size::Small)
.anchor(Corner::BottomLeft)
Color Palette Builder
struct ColorPalette {
colors: Vec<Entity<ColorPickerState>>,
}
impl ColorPalette {
fn add_color(&mut self, window: &mut Window, cx: &mut Context<Self>) {
let color_picker = cx.new(|cx| ColorPickerState::new(window, cx));
// Subscribe to color changes
cx.subscribe(&color_picker, |this, _, ev, _| match ev {
ColorPickerEvent::Change(color) => {
if let Some(color) = color {
this.update_palette_preview();
}
}
});
self.colors.push(color_picker);
cx.notify();
}
fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
h_flex()
.gap_2()
.children(
self.colors.iter().map(|color_picker| {
ColorPicker::new(color_picker).small()
})
)
.child(
Button::new("add-color")
.icon(IconName::Plus)
.ghost()
.on_click(cx.listener(|this, _, window, cx| {
this.add_color(window, cx);
}))
)
}
}
With Color Validation
let color_picker = cx.new(|cx| ColorPickerState::new(window, cx));
let _subscription = cx.subscribe(&color_picker, |this, _, ev, _| match ev {
ColorPickerEvent::Change(color) => {
if let Some(color) = color {
// Validate color accessibility
if this.validate_contrast(color) {
this.apply_color(color);
} else {
this.show_contrast_warning();
}
}
}
});
Accessibility
Keyboard Navigation
- Tab: Navigate to color picker button
- Enter/Space: Open/close color picker dropdown
- Escape: Close dropdown without selecting
- Arrow Keys: Navigate through color palette (when focused)
- Enter: Select highlighted color
- Tab: Navigate to hex input field within dropdown
Screen Reader Support
- Color picker button announces current color value
- Color swatches include color names and hex values
- Dropdown state changes are announced
- Hex input field provides real-time feedback
- Selected color is announced when changed
Focus Management
- Clear focus indicators on all interactive elements
- Focus is trapped within the dropdown when open
- Focus returns to trigger button when closed
- Logical tab order through color options
Color Accessibility
- High contrast borders around color swatches
- Color information available in multiple formats
- Sufficient touch target sizes for mobile devices
- Support for high contrast mode
- Color choices not solely dependent on color perception
Best Practices
- Provide text labels alongside color pickers
- Include color names or descriptions when possible
- Ensure sufficient contrast ratios for text over colored backgrounds
- Test with screen readers and keyboard navigation
- Consider colorblind users by providing additional visual cues
- Use semantic HTML structure for better accessibility