Component
combobox
dx components add comboboxAn autocomplete input + popover for picking a value from a filterable list of options.
Installation
Use the CLI command for the common path, or copy the component files manually.
Manual installation files
Copy the component source and CSS into your app. Import the shared theme CSS once near your app root.
use dioxus::prelude::*;
use dioxus_icons::lucide::{Check, ChevronsUpDown};
use dioxus_primitives::combobox::{
self, default_combobox_filter, ComboboxEmptyProps, ComboboxOptionProps,
};
use dioxus_primitives::{dioxus_attributes::attributes, merge_attributes};
#[derive(Props, Clone, PartialEq)]
pub struct ComboboxProps<T: Clone + PartialEq + 'static = String> {
#[props(default)]
pub value: Option<ReadSignal<Option<T>>>,
#[props(default)]
pub default_value: Option<T>,
#[props(default)]
pub on_value_change: Callback<Option<T>>,
#[props(default)]
pub disabled: ReadSignal<bool>,
#[props(default)]
pub open: ReadSignal<Option<bool>>,
#[props(default)]
pub default_open: ReadSignal<bool>,
#[props(default)]
pub on_open_change: Callback<bool>,
#[props(default)]
pub query: ReadSignal<Option<String>>,
#[props(default)]
pub default_query: ReadSignal<String>,
#[props(default)]
pub on_query_change: Callback<String>,
#[props(default = ReadSignal::new(Signal::new(true)))]
pub roving_loop: ReadSignal<bool>,
#[props(default = Callback::new(|(q, t): (String, String)| default_combobox_filter(&q, &t)))]
pub filter: Callback<(String, String), bool>,
#[props(default)]
pub placeholder: ReadSignal<String>,
#[props(default)]
pub aria_label: Option<String>,
#[props(default)]
pub list_aria_label: Option<String>,
#[props(extends = GlobalAttributes)]
pub attributes: Vec<Attribute>,
pub children: Element,
}
#[component]
pub fn Combobox<T: Clone + PartialEq + 'static>(props: ComboboxProps<T>) -> Element {
let base = attributes!(div { class: "dx-combobox" });
let merged = merge_attributes(vec![base, props.attributes]);
rsx! {
document::Link { rel: "stylesheet", href: asset!("/src/components/combobox/style.css") }
combobox::Combobox {
value: props.value,
default_value: props.default_value,
on_value_change: props.on_value_change,
disabled: props.disabled,
open: props.open,
default_open: props.default_open,
on_open_change: props.on_open_change,
query: props.query,
default_query: props.default_query,
on_query_change: props.on_query_change,
roving_loop: props.roving_loop,
filter: props.filter,
attributes: merged,
div { class: "dx-combobox-input-wrapper",
combobox::ComboboxInput {
class: "dx-combobox-input",
placeholder: props.placeholder,
aria_label: props.aria_label.clone(),
}
ChevronsUpDown {
class: "dx-combobox-expand-icon",
size: "16px",
}
}
combobox::ComboboxList {
class: "dx-combobox-list",
aria_label: props.list_aria_label.clone(),
{props.children}
}
}
}
}
#[component]
pub fn ComboboxEmpty(props: ComboboxEmptyProps) -> Element {
let base = attributes!(div { class: "dx-combobox-empty" });
let merged = merge_attributes(vec![base, props.attributes]);
rsx! {
document::Link { rel: "stylesheet", href: asset!("/src/components/combobox/style.css") }
combobox::ComboboxEmpty {
attributes: merged,
{props.children}
}
}
}
#[component]
pub fn ComboboxOption<T: Clone + PartialEq + 'static>(props: ComboboxOptionProps<T>) -> Element {
let base = attributes!(div { class: "dx-combobox-option" });
let merged = merge_attributes(vec![base, props.attributes]);
rsx! {
document::Link { rel: "stylesheet", href: asset!("/src/components/combobox/style.css") }
combobox::ComboboxOption::<T> {
value: props.value,
text_value: props.text_value,
disabled: props.disabled,
id: props.id,
index: props.index,
aria_label: props.aria_label,
aria_roledescription: props.aria_roledescription,
attributes: merged,
{props.children}
combobox::ComboboxItemIndicator {
Check {
class: "dx-combobox-check-icon",
size: "16px",
}
}
}
}
}Usage notes
The Combobox component is an autocomplete input with a filterable popup list.
Filtering preserves the order defined by the rendered ComboboxOption elements and their index
props. If you want query-dependent ranking, control query, sort your item data in user code,
render the options in that sorted order, and assign indexes from the sorted list.
Component Structure
let mut value = use_signal(|| None::<String>);
let mut query = use_signal(String::new);
Combobox::<String> {
value: Some(value.into()),
on_value_change: move |next: Option<String>| {
value.set(next);
},
query: Some(query()),
on_query_change: move |next| query.set(next),
placeholder: "Select framework...",
aria_label: "Select framework",
list_aria_label: "Frameworks",
ComboboxEmpty { "No framework found." }
ComboboxOption::<String> {
index: 0usize,
value: "next".to_string(),
text_value: "Next.js",
"Next.js"
}
}Variants
Alternative examples for common configurations.
controlled
svelte