Skip to content
PorabuildHeroGPUI component library
v0.14.0 · Apache-2.0

Colors

Color Field

Enter a color value as text.

Rust
use herogpui::components::color_picker::ColorField;

ColorField 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.

Usage

Runs in a view's render: self is the view holding this example's state and cx is its Context<Self>.

Rust
use herogpui::prelude::ColorField;
use herogpui::gpui::prelude::*;
use herogpui::gpui::px;
use herogpui::gpui;

let value = self.picker_color;

gpui::div()
    .flex()
    .flex_col()
    .w(px(256.))
    .gap(px(12.))
    .children(vec![ColorField::new("color-field", value)
        .state(self.demo_text("cf-usage", "#0085F5", cx))
        // v3's Usage is uncontrolled: `defaultValue="#0085F5"`.
        .default_value(value)
        .label("Color")
        .radius(px(4.))
        .into_any_element()])

Empty Value

ColorField accepts an explicit null value. The empty field keeps its label and placeholder, omits the swatch, and can be filled later. Runs in a view's render: self is the view holding this example's state and cx is its Context<Self>.

Rust
use herogpui::prelude::{ColorField, PickerColor};
use herogpui::gpui::prelude::*;
use herogpui::gpui::px;
use herogpui::gpui;

gpui::div()
    .flex()
    .flex_col()
    .w(px(256.))
    .gap(px(12.))
    .children(vec![ColorField::new("color-field-empty", None::<PickerColor>)
        .default_value(None::<PickerColor>)
        .state(self.demo_text("cf-empty", "", cx))
        .label("Brand color")
        .placeholder("#000000")
        .is_required(true)
        .into_any_element()])

Box Customisation

`height`, `padding_x` and `is_bare` cover both paths: the editable field here, and the static display box. The bare specimen is the editable path. Runs in a view's render: self is the view holding this example's state and cx is its Context<Self>.

Rust
use herogpui::prelude::ColorField;
use herogpui::gpui::prelude::*;
use herogpui::gpui::px;
use herogpui::gpui;

let value = self.picker_color;

gpui::div()
    .flex()
    .flex_col()
    .w(px(256.))
    .gap(px(12.))
    .children(vec![ColorField::new("color-field-custom-box", value)
        .state(self.demo_text("cf-custom-box", "#0085F5", cx))
        .label("Compact editable")
        .height(px(28.))
        .padding_x(px(8.))
        .is_bare(true)
        .font_family(MONO_FONT)
        .into_any_element()])

Also calls MONO_FONT (included when you copy).

Root Styling

`sx` refines the field's root, the column holding the label, the box and the description, on the editable and the static path alike; the box keeps its own chrome. Runs in a view's render: self is the view holding this example's state and cx is its Context<Self>.

Rust
use herogpui::prelude::ColorField;
use herogpui::gpui::prelude::*;
use herogpui::gpui::px;
use herogpui::gpui;

let value = self.picker_color;

gpui::div()
    .flex()
    .flex_col()
    .w(px(256.))
    .gap(px(12.))
    .children(vec![
        ColorField::new("color-field-sx-editable", value)
            .state(self.demo_text("cf-sx-editable", "#0085F5", cx))
            .label("Editable")
            .description("Padded, tinted column")
            .sx(|s| s.p(px(8.)).rounded(px(12.)).bg(gpui::hsla(0.58, 0.9, 0.5, 0.08)))
            .into_any_element(),
        ColorField::new("color-field-sx-static", value)
            .label("Static")
            .description("Same slot, display-only box")
            .sx(|s| s.p(px(8.)).rounded(px(12.)).bg(gpui::hsla(0.58, 0.9, 0.5, 0.08)))
            .into_any_element(),
    ])

Variants

Runs in a view's render: self is the view holding this example's state and cx is its Context<Self>.

Rust
use herogpui::prelude::{ColorField, FieldVariant};
use herogpui::gpui::prelude::*;
use herogpui::gpui::px;
use herogpui::gpui;

let value = self.picker_color;

gpui::div()
    .flex()
    .flex_col()
    .items_start()
    .justify_center()
    .gap(px(12.))
    .children(vec![
        ColorField::new("color-field-primary", value)
            .state(self.demo_text("cf-v-primary", "#0085F5", cx))
            .label("Primary")
            .into_any_element(),
        ColorField::new("color-field-secondary", value)
            .state(self.demo_text("cf-v-secondary", "#0085F5", cx))
            .label("Secondary")
            .variant(FieldVariant::Secondary)
            .into_any_element(),
    ])

On Surface

Runs in a view's render: self is the view holding this example's state and cx is its Context<Self>.

Rust
use herogpui::prelude::{ColorField, FieldVariant, Surface};
use herogpui::gpui::prelude::*;
use herogpui::gpui::px;
use herogpui::gpui;

let value = self.picker_color;

gpui::div()
    .flex()
    .flex_col()
    .items_start()
    .justify_center()
    .gap(px(12.))
    .children(vec![Surface::new()
        .padding(px(24.))
        .gap(px(16.))
        .child(
            ColorField::new("color-field-surface", value)
                .state(self.demo_text("cf-surface", "#0085F5", cx))
                .label("Color")
                .variant(FieldVariant::Secondary),
        )
        .into_any_element()])

With Description

Runs in a view's render: self is the view holding this example's state and cx is its Context<Self>.

Rust
use herogpui::prelude::ColorField;
use herogpui::gpui::prelude::*;
use herogpui::gpui::px;
use herogpui::gpui;

let value = self.picker_color;

gpui::div()
    .flex()
    .flex_col()
    .w(px(256.))
    .gap(px(12.))
    .children(vec![ColorField::new("color-field-desc", value)
        .state(self.demo_text("cf-desc", "#0085F5", cx))
        .label("Brand color")
        .description("Any CSS hex value")
        .into_any_element()])

Required Field

Runs in a view's render: self is the view holding this example's state and cx is its Context<Self>.

Rust
use herogpui::prelude::ColorField;
use herogpui::gpui::prelude::*;
use herogpui::gpui::px;
use herogpui::gpui;

let value = self.picker_color;

gpui::div()
    .flex()
    .flex_col()
    .w(px(256.))
    .gap(px(12.))
    .children(vec![ColorField::new("color-field-req", value)
        .state(self.demo_text("cf-req", "", cx))
        .label("Color")
        .is_required(true)
        .into_any_element()])

Disabled State

Runs in a view's render: self is the view holding this example's state and cx is its Context<Self>.

Rust
use herogpui::prelude::ColorField;
use herogpui::gpui::prelude::*;
use herogpui::gpui::px;
use herogpui::gpui;

let value = self.picker_color;

gpui::div()
    .flex()
    .flex_col()
    .w(px(256.))
    .gap(px(12.))
    .children(vec![ColorField::new("color-field-dis", value)
        .state(self.demo_text("cf-dis", "#0085F5", cx))
        .label("Color")
        .is_disabled(true)
        .into_any_element()])

Full Width

Runs in a view's render: self is the view holding this example's state and cx is its Context<Self>.

Rust
use herogpui::prelude::ColorField;
use herogpui::gpui::prelude::*;
use herogpui::gpui::px;
use herogpui::gpui;

let value = self.picker_color;

gpui::div()
    .w(px(400.))
    .child(gpui::div()
               .flex()
               .flex_col()
               .items_start()
               .justify_center()
               .gap(px(12.))
               .children(vec![
                       ColorField::new("color-field-full", value)
                           .state(self.demo_text("cf-full", "#0085F5", cx))
                           .label("Color")
                           .full_width(true)
                           .into_any_element(),
                       ColorField::new("color-field-full-display", value)
                           .label("Display color")
                           .full_width(true)
                           .into_any_element(),
                   ])
               .into_any_element())

Validation

Runs in a view's render: self is the view holding this example's state and cx is its Context<Self>.

Rust
use herogpui::prelude::ColorField;
use herogpui::gpui::prelude::*;
use herogpui::gpui::px;
use herogpui::gpui;

let value = self.picker_color;

gpui::div()
    .flex()
    .flex_col()
    .w(px(256.))
    .gap(px(12.))
    .children(vec![ColorField::new("color-field-invalid", value)
        .state(self.demo_text("cf-invalid", "not-a-color", cx))
        .label("Color")
        .is_required(true)
        .is_invalid(true)
        .validation_errors(["Enter a valid hex colour"])
        .into_any_element()])

Channel Editing

Edit individual HSL channels: Runs in a view's render: self is the view holding this example's state and cx is its Context<Self>.

Rust
use herogpui::prelude::{ColorChannel, ColorField, ColorSpace, ColorSwatch};
use herogpui::gpui::prelude::*;
use herogpui::gpui::px;
use herogpui::gpui;

let value = self.picker_color;

gpui::div()
    .flex()
    .flex_col()
    .items_start()
    .justify_center()
    .gap(px(12.))
    .children(vec![gpui::div()
                       .flex()
                       .flex_wrap()
                       .items_center()
                       .justify_center()
                       .gap(px(12.))
                       .children(vec![
                               ColorField::new("color-field-ch-hue", value)
                                       .state(self.demo_text("cf-ch-hue", "", cx))
                                       // `colorSpace` names the channel set; `channel`
                                       // picks one of them.
                                       .color_space(ColorSpace::Hsl)
                                       .channel(ColorChannel::Hue)
                                       // `ColorField.Suffix` -- the unit after the value.
                                       .suffix(gpui::div().child("\u{00b0}"))
                                       .label("Hue")
                                       .into_any_element(),
                               ColorField::new("color-field-ch-sat", value)
                                   .state(self.demo_text("cf-ch-sat", "", cx))
                                   .channel(ColorChannel::Saturation)
                                   .label("Saturation")
                                   .into_any_element(),
                               ColorField::new("color-field-ch-light", value)
                                   .state(self.demo_text("cf-ch-light", "", cx))
                                   .channel(ColorChannel::Lightness)
                                   .label("Lightness")
                                   .into_any_element(),
                               ColorSwatch::new(value).into_any_element(),
                           ])
                       .into_any_element(),])

Controlled

Runs in a view's render: self is the view holding this example's state and cx is its Context<Self>.

Rust
use herogpui::prelude::{ActiveTheme, ColorField, ColorSwatch, PickerColor};
use herogpui::gpui::prelude::*;
use herogpui::gpui::{App, px};
use herogpui::gpui;

let value = self.picker_color;

gpui::div()
    .flex()
    .flex_col()
    .items_start()
    .justify_center()
    .gap(px(12.))
    .children(vec![
        ColorField::new("color-field-ctl", value)
            .state(self.demo_text("cf-ctl", "#0085F5", cx))
            .label("Color")
            .on_change(cx.listener(
                |this, parsed: &Option<PickerColor>, _, cx| {
                    if let Some(c) = parsed {
                        this.picker_color = *c;
                    }
                    cx.notify();
                },
            ))
            .into_any_element(),
        gpui::div()
            .flex()
            .flex_wrap()
            .items_center()
            .justify_center()
            .gap(px(12.))
            .children(vec![
                        ColorSwatch::new(value).into_any_element(),
                        para(&format!("Value: {}", value.to_hex()), cx),
                    ])
            .into_any_element(),
    ])

Also calls para (included when you copy).

Render Function

Runs in a view's render: self is the view holding this example's state and cx is its Context<Self>.

Rust
use herogpui::prelude::ColorField;
use herogpui::gpui::prelude::*;
use herogpui::gpui::px;
use herogpui::gpui;

let value = self.picker_color;

gpui::div()
    .flex()
    .flex_col()
    .items_start()
    .justify_center()
    .gap(px(12.))
    .children(vec![{
        let state = self.demo_text("cf-render", "#0085F5", cx);
        let inner = state.clone();
        ColorField::new("color-field-render-root", value)
            .state(state)
            .is_required(true)
            .content(move |field| {
                gpui::div()
                    .flex()
                    .flex_col()
                    .gap(px(4.))
                    .child(
                        ColorField::new("color-field-render-input", value)
                            .state(inner.clone())
                            .label("Rendered color")
                            .is_disabled(field.is_disabled)
                            .is_invalid(field.is_invalid)
                            .is_read_only(field.is_read_only)
                            .is_required(field.is_required),
                    )
                    .child(format!(
                        "required={} focused={} focus-within={} focus-visible={}",
                        field.is_required,
                        field.is_focused,
                        field.is_focus_within,
                        field.is_focus_visible,
                    ))
                    .into_any_element()
            })
            .into_any_element()
    }])

Form Example

Runs in a view's render: self is the view holding this example's state and cx is its Context<Self>.

Rust
use herogpui::prelude::{Button, ColorField, Form, FormField};
use herogpui::gpui::prelude::*;
use herogpui::gpui::px;
use herogpui::gpui;

let value = self.picker_color;

gpui::div()
    .flex()
    .flex_col()
    .items_start()
    .justify_center()
    .gap(px(12.))
    .children(vec![{
        let state = self.demo_text("cf-form", "#0085F5", cx);
        Form::new()
            .field(FormField::text(state.clone()).name("color"))
            .child(
                ColorField::new("color-field-form", value)
                    .state(state)
                    .label("Brand color")
                    .name("color")
                    .is_required(true),
            )
            .child(Button::new("color-field-form-submit").label("Save"))
            .into_any_element()
    }])

Hex value

Runs in a view's render: self is the view holding this example's state and cx is its Context<Self>.

Rust
use herogpui::prelude::{ColorField, PickerColor};
use herogpui::gpui::prelude::*;
use herogpui::gpui::px;
use herogpui::gpui;

let value = self.picker_color;

gpui::div()
    .flex()
    .flex_col()
    .w(px(256.))
    .gap(px(12.))
    .children(vec![ColorField::new("color-field-hex", value)
        .state(self.demo_text("cf-hex", "#0085F5", cx))
        .label("Brand color")
        .description("Type a hex value such as #0085F5.")
        .placeholder(value.to_hex())
        .on_change(cx.listener(|this, parsed: &Option<PickerColor>, _, cx| {
            // Unparseable text reports None; the swatch
            // holds its last good colour.
            if let Some(c) = parsed {
                this.picker_color = *c;
            }
            cx.notify();
        },))
        .into_any_element()])

Blur Behaviour

Commits a colour field on blur: when focus leaves, text that does not parse to a colour restores the last committed value, valid text is left alone, and an emptied field stays empty. `on_blur` hooks the focus loss itself and fires ahead of that revert. Runs in a view's render: self is the view holding this example's state and cx is its Context<Self>.

Rust
use herogpui::prelude::{ColorField, Input};
use herogpui::gpui::prelude::*;
use herogpui::gpui::px;
use herogpui::gpui;

let value = self.picker_color;

gpui::div()
    .flex()
    .flex_col()
    .w(px(256.))
    .gap(px(12.))
    .children(vec![{
        let blurs = self.demo_text("cf-blur-log", "not blurred yet", cx);
        ColorField::new("color-field-blur", value)
            .state(self.demo_text("cf-blur", "#0085F5", cx))
            .default_value(value)
            .label("Color")
            .on_blur(move |_, cx| {
                blurs.update(cx, |state, cx| {
                    state.set_value("blur: focus left the field");
                    cx.notify();
                });
            })
            .into_any_element()
    },
    Input::new(self.demo_text("cf-blur-log", "not blurred yet", cx))
        .is_read_only(true)
        .into_any_element()])

Read-only display

Runs in a view's render: self is the view holding this example's state and cx is its Context<Self>.

Rust
use herogpui::prelude::ColorField;
use herogpui::gpui::prelude::*;
use herogpui::gpui::px;
use herogpui::gpui;

let value = self.picker_color;

gpui::div()
    .flex()
    .flex_col()
    .w(px(256.))
    .gap(px(12.))
    .children(vec![ColorField::new("color-field-display", value)
        .label("Current value")
        .description("Without a text state the field is a display.")
        .into_any_element()])

Single channel

Runs in a view's render: self is the view holding this example's state and cx is its Context<Self>.

Rust
use herogpui::prelude::{ColorChannel, ColorField};
use herogpui::gpui::prelude::*;
use herogpui::gpui::px;
use herogpui::gpui;

let value = self.picker_color;

gpui::div()
    .flex()
    .flex_wrap()
    .items_center()
    .justify_center()
    .gap(px(12.))
    .children(vec![
        ColorField::new("color-field-hue", value)
            .channel(ColorChannel::Hue)
            .label("Hue")
            .into_any_element(),
        ColorField::new("color-field-red", value)
            .channel(ColorChannel::Red)
            .label("Red")
            .into_any_element(),
    ])

Helpers used by these examples

Plain functions over the public API, defined once here and copied with each example that calls them.

MONO_FONT
const MONO_FONT: &str = if cfg!(target_arch = "wasm32") {
    // The web shell bundles JetBrains Mono; the literal family "monospace"
    // resolves to nothing there and panics text resolution.
    "JetBrains Mono"
} else if cfg!(target_os = "macos") {
    "Menlo"
} else {
    "Consolas"
};
para
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

ColorFieldColorSwatch

Color Field 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 Field 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

Color Field styling
MethodValuesDescription
full_width(bool)true | falseStretches the root and input group in editable and display modes.
variant(FieldVariant)primary | secondarySelects field or default fill and primary shadow.
Rust
// 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: 35 entries ported, 5 partial, 12 not ported. Partial rows are marked in the tables; entries not ported are listed under each table with the reason.

Builders

Color Field builders
BuilderValuesDefaultDescription
content(render)AnyElement | render closure—Replacement content receives disabled, invalid, read-only, required, focused, focus-within, and focus-visible state.
full_width(bool)true | falsefalseStretches the root and input group in editable and display modes.
focus_ring(bool)true | falsetrueGPUI extension: hides only the editable field's visual focus ring while retaining focus and editing.
new(id, value)string—Stable GPUI element identity is required by the constructor.
new(id, Option<PickerColor>)Color | null—Controlled color values may be concrete or null; null renders the documented empty field and onChange can return None while text is incomplete.
default_value(Option<PickerColor>)Color | null—Seeds picker-owned state with a concrete color or an explicit null empty value; the outer Rust Option distinguishes omission from null.
on_change(callback)Fn(Color | null) -> ()—Reports a parsed color or None while text is incomplete or invalid.
on_blur(callback)Fn(FocusEvent) -> ()—Focus loss commits the field like onBlur commit: unparseable text restores the formatted last-committed value while valid text and an emptied field are untouched. The hook fires ahead of that built-in revert, the way chains the caller's onBlur ahead of commit.
color_space(ColorSpace)ColorSpace—Selects the channel interpretation when channel is present.
channel(ColorChannel)ColorChannel—Switches from hexadecimal editing to one numeric channel.
is_required(bool)true | falsefalseMarks the label and form field required; an empty null value is treated as missing during native submission.
is_invalid(bool)true | false—Forces invalid chrome and render state.
validate(callback)Fn(Color) -> ValidationError | true | null—Custom validation contributes to field chrome, form validity, error text, and render state.
validation_behavior(ValidationBehavior)native | ariaValidationBehavior::NativeNative blocks submission; Allow exposes invalid state without blocking.
is_disabled(bool)true | falsefalseRemoves editing, focus, wheel changes, and successful form submission.
is_read_only(bool)true | falsefalseKeeps the editable input focusable while preventing changes.
is_wheel_disabled(bool)true | falsefalseSuppresses focused wheel stepping for channel fields.
name(text) + form_field()string—Registers the current hex text or channel number for FormData.
auto_focus(bool)true | falsefalseFocuses the editable input on its first render.
variant(FieldVariant)primary | secondaryFieldVariant::PrimarySelects field or default fill and primary shadow.
placeholder(text)string—Shows caller text, or the resolved current color when omitted.
built-in ColorSwatchPartialAnyElement—The built-in ColorSwatch follows the current color and is omitted for the null empty state; arbitrary replacement remains unavailable.
suffix(element)AnyElement—Caller content remains present in editable and display compositions.
Not ported12 HeroUI entries not ported
Color Field builders not ported
HeroUI v3Why it is not ported
ColorField.classNameBrowser styles are unavailable.
ColorField.styleBrowser inline styles are unavailable.
ColorField.renderRoot-element substitution is unavailable.
ColorField.aria-labelGPUI exposes no accessibility tree attribute surface.
ColorField.aria-labelledbyGPUI exposes no accessibility tree attribute surface.
ColorField.aria-describedbyGPUI exposes no accessibility tree attribute surface.
ColorField.aria-detailsGPUI exposes no accessibility tree attribute surface.
ColorField.Group.classNameBrowser styles are unavailable.
ColorField.Group.renderThe group cannot be replaced independently.
ColorField.Input.classNameBrowser styles are unavailable.
ColorField.Prefix.classNameBrowser styles are unavailable.
ColorField.Suffix.classNameBrowser styles are unavailable.

Parts

Color Field parts
PartDescription
ColorFieldValue, validation, form, and complete render-state owner.
ColorFieldPartialOptional string label with required, disabled, and invalid state; composes field::Label.
ColorFieldField chrome drawn by ColorField surrounding prefix, input, and suffix; the input is a composed Input.
ColorSwatchPartialFixed current-color swatch; arbitrary replacement is unavailable.
ColorFieldState-backed text input with parsing, channel keys, wheel editing, and focus. Each simultaneously rendered editable field needs its own input::InputState identity.
ColorFieldCaller-provided trailing content in placeholder color.
ColorFieldPartialOptional helper text replaced by resolved error content when invalid; composes field::Description.
ColorFieldPartialResolved controlled, server, or validator message handed to the composed Input's error_message; arbitrary child composition is unavailable.

States

Color Field states
StateBuilderDescription
Invalidvalidation::resolveHides description, shows the resolved message, draws danger chrome, blocks native forms, and reaches render state.
Requiredis_requiredMarks the label and reaches render state; a null or empty color fails native required validation.
Disabledis_disabledDims the group, removes input and wheel behavior, omits FormData, and reaches render state.
Read onlyis_read_onlyKeeps the editable input focusable but blocks mutations and reaches render state.
FocusedColorFieldRenderStateReports focus on the state-backed input.
Focus withinfocus_handle.contains_focusedFocus anywhere in the composed field drives focused chrome and render state.
Focus visiblefocus_visibleKeyboard-origin focus reaches the render function and the shared field ring.
Hoveredhover_fade_with_duration_and_easing(150ms, EaseSmooth)Enabled, unfocused groups interpolate the field/default hover fill over 150ms and apply the field-hover border endpoint.