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

Forms

Checkbox Group

A group of checkboxes with shared state.

Rust
use herogpui::components::checkbox::CheckboxGroup;

CheckboxGroup 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

Option labels use 14px/20px medium text; descriptions use 12px/16px regular text. An element expression with window: &mut Window and cx: &mut App in scope.

Rust
use herogpui::prelude::{CheckboxGroup, CheckboxOption};
use herogpui::gpui::prelude::*;
use herogpui::gpui::px;
use herogpui::gpui;

let group_options = || {
    vec![
        CheckboxOption::new("email", "Email").description("Product news and offers"),
        CheckboxOption::new("sms", "SMS"),
        CheckboxOption::new("push", "Push").is_disabled(true),
    ]
};

gpui::div()
    .flex()
    .flex_col()
    .items_start()
    .justify_center()
    .gap(px(12.))
    .children(vec![CheckboxGroup::new("checkbox-group", group_options())
        .label("Notifications")
        .into_any_element()])

In Surface

An element expression with window: &mut Window and cx: &mut App in scope.

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

let group_options = || {
    vec![
        CheckboxOption::new("email", "Email").description("Product news and offers"),
        CheckboxOption::new("sms", "SMS"),
        CheckboxOption::new("push", "Push").is_disabled(true),
    ]
};

gpui::div()
    .flex()
    .flex_col()
    .items_start()
    .justify_center()
    .gap(px(12.))
    .children(vec![Surface::new()
        .padding(px(24.))
        .child(
            CheckboxGroup::new("checkbox-group-surface", group_options())
                .label("Notifications")
                .variant(FieldVariant::Secondary),
        )
        .into_any_element()])

Disabled

An element expression with window: &mut Window and cx: &mut App in scope.

Rust
use herogpui::prelude::{CheckboxGroup, CheckboxOption};
use herogpui::gpui::prelude::*;
use herogpui::gpui::px;
use herogpui::gpui;

let group_options = || {
    vec![
        CheckboxOption::new("email", "Email").description("Product news and offers"),
        CheckboxOption::new("sms", "SMS"),
        CheckboxOption::new("push", "Push").is_disabled(true),
    ]
};

gpui::div()
    .flex()
    .flex_col()
    .items_start()
    .justify_center()
    .gap(px(12.))
    .children(vec![CheckboxGroup::new("checkbox-group-disabled", group_options())
        .label("Notifications")
        .is_disabled(true)
        .into_any_element()])

Indeterminate

A "select all" checkbox pairs with the group: it is indeterminate while only some children are selected. 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::{Checkbox, CheckboxGroup, CheckboxOption};
use herogpui::gpui::prelude::*;
use herogpui::gpui::{SharedString, px};
use herogpui::gpui;
use std::collections::HashSet;

let selected = self.checkbox_group.clone();
let group_options = || {
    vec![
        CheckboxOption::new("email", "Email").description("Product news and offers"),
        CheckboxOption::new("sms", "SMS"),
        CheckboxOption::new("push", "Push").is_disabled(true),
    ]
};

gpui::div()
    .flex()
    .flex_col()
    .items_start()
    .justify_center()
    .gap(px(12.))
    .children(vec![
        Checkbox::new("checkbox-group-all")
            .is_selected(selected.len() == 3)
            .is_indeterminate(!selected.is_empty() && selected.len() < 3)
            .label(gpui::div().child("All notifications"))
            .on_change(cx.listener(|this, all: &bool, _, cx| {
                this.checkbox_group = if *all {
                    ["email", "sms", "push"]
                        .into_iter()
                        .map(SharedString::from)
                        .collect()
                } else {
                    HashSet::new()
                };
                cx.notify();
            }))
            .into_any_element(),
        CheckboxGroup::new("checkbox-group-ind", group_options())
            .value(selected.iter().cloned())
            .on_change(cx.listener(|this, keys: &HashSet<SharedString>, _, cx| {
                this.checkbox_group = keys.clone();
                cx.notify();
            }))
            .into_any_element(),
    ])

Controlled

The selected set lives in the caller and is fed back through `value`; the caption prints the live set. 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, CheckboxGroup, CheckboxOption};
use herogpui::gpui::prelude::*;
use herogpui::gpui::{App, SharedString, px};
use herogpui::gpui;
use std::collections::HashSet;

let selected = self.checkbox_group.clone();

gpui::div()
    .flex()
    .flex_col()
    .items_start()
    .justify_center()
    .gap(px(12.))
    .children(vec![
        CheckboxGroup::new(
            "checkbox-group-controlled",
            vec![
                CheckboxOption::new("coding", "Coding"),
                CheckboxOption::new("design", "Design"),
                CheckboxOption::new("writing", "Writing"),
            ],
        )
        .label("Your skills")
        .value(selected.iter().cloned())
        .on_change(cx.listener(|this, keys: &HashSet<SharedString>, _, cx| {
            this.checkbox_group = keys.clone();
            cx.notify();
        }))
        .into_any_element(),
        para(
            &format!(
                "Selected: {}",
                {
                    let mut names: Vec<&str> =
                        selected.iter().map(|k| k.as_ref()).collect();
                    names.sort();
                    if names.is_empty() {
                        "None".to_owned()
                    } else {
                        names.join(", ")
                    }
                }
            ),
            cx,
        ),
    ])

Also calls para (included when you copy).

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::{CheckboxGroup, CheckboxOption};
use herogpui::gpui::prelude::*;
use herogpui::gpui::{SharedString, px};
use herogpui::gpui;
use std::collections::HashSet;

let selected = self.checkbox_group.clone();
let group_options = || {
    vec![
        CheckboxOption::new("email", "Email").description("Product news and offers"),
        CheckboxOption::new("sms", "SMS"),
        CheckboxOption::new("push", "Push").is_disabled(true),
    ]
};

gpui::div()
    .flex()
    .flex_col()
    .items_start()
    .justify_center()
    .gap(px(12.))
    .children(vec![CheckboxGroup::new("checkbox-group-validate", group_options())
        .label("Notifications")
        .is_required(true)
        .is_invalid(selected.is_empty())
        .error_message("Pick at least one channel")
        .value(selected.iter().cloned())
        .on_change(cx.listener(|this, keys: &HashSet<SharedString>, _, cx| {
            this.checkbox_group = keys.clone();
            cx.notify();
        }))
        .into_any_element()])

Features and Add-ons Example

An element expression with window: &mut Window and cx: &mut App in scope.

Rust
use herogpui::prelude::{CheckboxGroup, CheckboxOption};
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![CheckboxGroup::new(
        "checkbox-group-addons",
        vec![
            CheckboxOption::new("analytics", "Analytics")
                .description("Usage dashboards and funnels"),
            CheckboxOption::new("backups", "Daily backups")
                .description("Restore any of the last 30 days"),
            CheckboxOption::new("sso", "Single sign-on")
                .description("SAML and OIDC"),
        ],
    )
    .label("Add-ons")
    .description("Billed monthly, cancel any time.")
    .into_any_element()])

With Custom Indicator

A custom indicator belongs to a standalone Checkbox, not to this port's group options; here two standalone checkboxes draw hearts. An element expression with window: &mut Window and cx: &mut App in scope.

Rust
use herogpui::prelude::{Checkbox, CheckboxGroup, icons};
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![
        Checkbox::new("checkbox-group-ci-1")
            .default_selected(true)
            .indicator(move |state| {
                if state.is_selected {
                    gpui::svg()
                        .size(px(10.))
                        .path(icons::HEART_FILL)
                        .text_color(gpui::white())
                        .into_any_element()
                } else {
                    gpui::div().into_any_element()
                }
            })
            .label(gpui::div().child("Email"))
            .into_any_element(),
        Checkbox::new("checkbox-group-ci-2")
            .indicator(move |state| {
                if state.is_selected {
                    gpui::svg()
                        .size(px(10.))
                        .path(icons::HEART_FILL)
                        .text_color(gpui::white())
                        .into_any_element()
                } else {
                    gpui::div().into_any_element()
                }
            })
            .label(gpui::div().child("SMS"))
            .into_any_element(),
    ])

Vertical

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::{CheckboxGroup, CheckboxOption};
use herogpui::gpui::prelude::*;
use herogpui::gpui::{SharedString, px};
use herogpui::gpui;
use std::collections::HashSet;

let selected = self.checkbox_group.clone();
let group_options = || {
    vec![
        CheckboxOption::new("email", "Email").description("Product news and offers"),
        CheckboxOption::new("sms", "SMS"),
        CheckboxOption::new("push", "Push").is_disabled(true),
    ]
};
let options = group_options();

gpui::div()
    .flex()
    .flex_col()
    .items_start()
    .justify_center()
    .gap(px(12.))
    .children(vec![CheckboxGroup::new("checkbox-group", options.clone())
        .label("Notifications")
        .description("Pick how we reach you.")
        .value(selected.iter().cloned())
        .on_change(cx.listener(|this, keys: &HashSet<SharedString>, _, cx| {
            this.checkbox_group = keys.clone();
            cx.notify();
        }))
        .into_any_element()])

Horizontal & invalid

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::{CheckboxGroup, CheckboxOption, Orientation};
use herogpui::gpui::prelude::*;
use herogpui::gpui::{SharedString, px};
use herogpui::gpui;
use std::collections::HashSet;

let selected = self.checkbox_group.clone();
let group_options = || {
    vec![
        CheckboxOption::new("email", "Email").description("Product news and offers"),
        CheckboxOption::new("sms", "SMS"),
        CheckboxOption::new("push", "Push").is_disabled(true),
    ]
};
let options = group_options();

gpui::div()
    .flex()
    .flex_col()
    .items_start()
    .justify_center()
    .gap(px(12.))
    .children(vec![CheckboxGroup::new("checkbox-group-h", options)
        .label("Channels")
        .orientation(Orientation::Horizontal)
        .error_message("Choose at least two channels.")
        .value(selected.iter().cloned())
        .on_change(cx.listener(|this, keys: &HashSet<SharedString>, _, cx| {
            this.checkbox_group = keys.clone();
            cx.notify();
        }))
        .into_any_element()])

Uncontrolled

An element expression with window: &mut Window and cx: &mut App in scope.

Rust
use herogpui::prelude::{CheckboxGroup, CheckboxOption};
use herogpui::gpui::prelude::*;
use herogpui::gpui::{SharedString, px};
use herogpui::gpui;

let group_options = || {
    vec![
        CheckboxOption::new("email", "Email").description("Product news and offers"),
        CheckboxOption::new("sms", "SMS"),
        CheckboxOption::new("push", "Push").is_disabled(true),
    ]
};

gpui::div()
    .flex()
    .flex_col()
    .items_start()
    .justify_center()
    .gap(px(12.))
    .children(vec![CheckboxGroup::new("checkbox-group-unc", group_options())
        .label("Channels")
        .default_value(vec![SharedString::from("email")])
        .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.

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

CheckboxGroup

Checkbox Group is assembled from these builders. The API reference lists each one.

API reference

Against HeroUI v3.2.6: 22 entries ported, 1 partial, 6 not ported. Partial rows are marked in the tables; entries not ported are listed under each table with the reason.

Builders

Checkbox Group builders
BuilderValuesDefaultDescription
value(keys)string[]โ€”Current selected values (controlled).
default_value(keys)string[]โ€”Initial selected values (uncontrolled).
on_change(callback)Fn(value: string[]) -> ()โ€”Handler called with the complete selected set.
is_disabled(bool)true | falsefalseDisables every option and omits the group from form submission.
is_required(bool)true | falsefalseRequires at least one enabled option to be selected.
is_read_only(bool)true | falsefalseKeeps enabled options focusable while preventing changes.
is_invalid(bool)true | falsefalseMarks the group and every option invalid.
name(value)stringโ€”Submitted form field name for the selected values.
new(id, options)PartialAnyElement | CheckboxGrouprender closureโ€”Compound group content; takes options plus label/description/error builders.
Not ported6 HeroUI entries not ported
Checkbox Group builders not ported
HeroUI v3Why it is not ported
CheckboxGroup.renderOverrides the group root element.
Render Props.valueCurrent selection supplied to a group render function.
Render Props.isDisabledCurrent disabled state supplied to a group render function.
Render Props.isReadOnlyCurrent read-only state supplied to a group render function.
Render Props.isInvalidCurrent invalid state supplied to a group render function.
Render Props.isRequiredCurrent required state supplied to a group render function.

Parts

Checkbox Group parts
PartDescription
CheckboxGroupGroup value, validation, form and option composition owner.
CheckboxGroupGroup label with required, disabled and invalid state.
CheckboxGroupOptional group or per-option help text.
CheckboxGroupOne generated checkbox per option.
CheckboxGroupOption label and optional description content.
CheckboxGroupSelection control inherited from Checkbox.
CheckboxGroupSelection mark inherited from Checkbox.
CheckboxGroupGroup validation message rendered in place of the description.

States

Checkbox Group states
StateBuilderDescription
DisabledCheckboxGroup::is_disabledEvery option is disabled and omitted from the successful form value.
Read onlyCheckboxGroup::is_read_only -> Checkbox::is_read_onlyOptions remain focusable but cannot toggle.
Invalidis_invalidDanger treatment propagates to each option and the field error.
RequiredFormField::is_requiredNative form validation requires one enabled selected value.
Controlledutil::controlled(Some(value))The caller owns the selected set; callbacks report without mutating behind it.
Uncontrolledutil::controlled(None)The group owns and resets its keyed selected set.