Checkbox Group
A group of checkboxes with shared state.
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.
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.
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()])An element expression with window: &mut Window and cx: &mut App in scope.
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()])An element expression with window: &mut Window and cx: &mut App in scope.
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()])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>.
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(),
])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>.
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).
Runs in a view's render: self is the view holding this example's state and cx is its Context<Self>.
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()])An element expression with window: &mut Window and cx: &mut App in scope.
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()])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.
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(),
])Runs in a view's render: self is the view holding this example's state and cx is its Context<Self>.
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()])Runs in a view's render: self is the view holding this example's state and cx is its Context<Self>.
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()])An element expression with window: &mut Window and cx: &mut App in scope.
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.
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
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
| Builder | Values | Default | Description |
|---|---|---|---|
value( | string[] | โ | Current selected values (controlled). |
default_value( | string[] | โ | Initial selected values (uncontrolled). |
on_change( | Fn( | โ | Handler called with the complete selected set. |
is_disabled( | true | | false | Disables every option and omits the group from form submission. |
is_required( | true | | false | Requires at least one enabled option to be selected. |
is_read_only( | true | | false | Keeps enabled options focusable while preventing changes. |
is_invalid( | true | | false | Marks the group and every option invalid. |
name( | string | โ | Submitted form field name for the selected values. |
new(Partial | AnyElement | | โ | Compound group content; takes options plus label/description/error builders. |
Not ported6 HeroUI entries not ported
| HeroUI v3 | Why it is not ported |
|---|---|
CheckboxGroup.render | Overrides the group root element. |
Render Props.value | Current selection supplied to a group render function. |
Render Props.isDisabled | Current disabled state supplied to a group render function. |
Render Props.isReadOnly | Current read-only state supplied to a group render function. |
Render Props.isInvalid | Current invalid state supplied to a group render function. |
Render Props.isRequired | Current required state supplied to a group render function. |
Parts
| Part | Description |
|---|---|
CheckboxGroup | Group value, validation, form and option composition owner. |
CheckboxGroup | Group label with required, disabled and invalid state. |
CheckboxGroup | Optional group or per-option help text. |
CheckboxGroup | One generated checkbox per option. |
CheckboxGroup | Option label and optional description content. |
CheckboxGroup | Selection control inherited from Checkbox. |
CheckboxGroup | Selection mark inherited from Checkbox. |
CheckboxGroup | Group validation message rendered in place of the description. |
States
| State | Builder | Description |
|---|---|---|
Disabled | CheckboxGroup::is_disabled | Every option is disabled and omitted from the successful form value. |
Read only | CheckboxGroup::is_read_only -> Checkbox::is_read_only | Options remain focusable but cannot toggle. |
Invalid | is_invalid | Danger treatment propagates to each option and the field error. |
Required | FormField::is_required | Native form validation requires one enabled selected value. |
Controlled | util::controlled(Some(value)) | The caller owns the selected set; callbacks report without mutating behind it. |
Uncontrolled | util::controlled(None) | The group owns and resets its keyed selected set. |