Dropdown
Display a menu of actions anchored to a trigger.
use herogpui::components::dropdown::{Dropdown, MenuItem};Dropdown 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.
The menu positions against the measured trigger: all 22 union placements flip to the side with more room when the preferred side cannot fit, keep a 12px cross-axis viewport inset, and cap the scroller to the available height with short menus keeping their natural height. 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, Button, Dropdown, MenuItem, Variant};
use herogpui::gpui::prelude::*;
use herogpui::gpui::{App, SharedString, px};
use herogpui::gpui;
let is_open = self.dropdown_open;
let selected = self
.dropdown_selected
.clone()
.unwrap_or_else(|| SharedString::from("none"));
let items = vec![
MenuItem::new("new", "New file").shortcut("Ctrl N"),
MenuItem::new("copy", "Copy link").shortcut("Ctrl C"),
MenuItem::Separator,
MenuItem::new("delete", "Delete file").danger(),
];
gpui::div()
.flex()
.flex_col()
.items_start()
.justify_center()
.gap(px(12.))
.children(vec![
Dropdown::new(
"dropdown-trigger-dd",
Button::new("dropdown-trigger")
.label("Actions")
.variant(Variant::Secondary),
items,
is_open,
)
.id("dropdown-trigger-dd")
.radius(px(4.))
.on_open_change(cx.listener(|this, open: &bool, _, cx| {
this.dropdown_open = *open;
cx.notify();
}))
.on_action(cx.listener(|this, key: &SharedString, _, cx| {
this.dropdown_selected = Some(key.clone());
this.dropdown_open = false;
cx.notify();
}))
.into_any_element(),
para(&format!("Last action: {selected}"), cx),
])Also calls para (included when you copy).
`row_hover_bg` names the fill a hovered menu row takes, in place of `--default`. An element expression with window: &mut Window and cx: &mut App in scope.
use herogpui::prelude::{ActiveTheme, Button, Dropdown, MenuItem, Variant};
use herogpui::gpui::prelude::*;
use herogpui::gpui::px;
use herogpui::gpui;
let plain = || {
vec![
MenuItem::new("new", "New file"),
MenuItem::new("open", "Open file"),
MenuItem::new("save", "Save"),
]
};
gpui::div()
.flex()
.flex_col()
.items_start()
.justify_center()
.gap(px(12.))
.children(vec![Dropdown::uncontrolled(
"dd-hover-trigger",
Button::new("dropdown-hover")
.label("Actions")
.variant(Variant::Secondary),
plain(),
)
.row_hover_bg(cx.colors().accent.soft())
.into_any_element()])`separator_inset` and `separator_thickness` (on `Menu`, or on `MenuStyle` for a whole theme) give the rule a per-edge inset inside wider panel bounds and an explicit thickness. Unset, the rule keeps v3's proportional inset: 94% of the panel width, centred. The values below are AppKit's own menu separator: 15pt in on each side, 1pt thick. Runs in a view's render: self is the view holding this example's state and cx is its Context<Self>.
use herogpui::prelude::{Button, Dropdown, Menu, MenuItem};
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![
Button::new("dropdown-inset-show").label("Show menu")
.on_press(cx.listener(|this, _, _, cx| { this.set_demo_flag("dd-inset", true); cx.notify(); })).into_any_element(),
if self.demo_flag("dd-inset", false) {
Menu::new("dropdown-inset", vec![
MenuItem::new("cut", "Cut"),
MenuItem::new("copy", "Copy"),
MenuItem::Separator,
MenuItem::new("paste", "Paste"),
])
.panel_min_width(px(200.)).panel_max_width(px(200.))
.separator_inset(px(15.))
.separator_thickness(px(1.))
.animate_entry(false)
.on_dismiss(cx.listener(|this, _: &bool, _, cx| { this.set_demo_flag("dd-inset", false); cx.notify(); }))
.into_any_element()
} else { gpui::div().into_any_element() },
])`MenuItem::is_interactive(true)` hands the row's interaction to the element `item_content` draws for it, so a trailing secondary control answers the press instead of the row picking and closing the menu. The row stays a keyboard stop; Enter and Space belong to the control. A popup the control opens needs no extra wiring — it becomes the topmost overlay, and the menu's own dismissals stand down while it is up. Runs in a view's render: self is the view holding this example's state and cx is its Context<Self>.
use herogpui::prelude::{Button, Dropdown, Menu, MenuItem, PickerItem, Select};
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![
Button::new("dropdown-inline-show").label("Show menu")
.on_press(cx.listener(|this, _, _, cx| { this.set_demo_flag("dd-inline", true); cx.notify(); })).into_any_element(),
if self.demo_flag("dd-inline", false) {
Menu::new("dropdown-inline", vec![
MenuItem::new("reload", "Reload"),
MenuItem::new("layout", "Layout").is_interactive(true),
])
.panel_min_width(px(260.)).panel_max_width(px(260.))
.animate_entry(false)
.item_content(|key, _| match key.as_ref() {
"layout" => gpui::div()
.flex()
.items_center()
.justify_between()
.gap(px(8.))
.w_full()
.child("Layout")
.child(
Select::new(
"dropdown-inline-layout",
vec![
PickerItem::new("side", "Side by side"),
PickerItem::new("stack", "Stacked"),
],
)
.default_value(Some("side".into()))
.height(px(24.))
.padding_x(px(6.))
.trigger_text_size(px(12.)),
)
.into_any_element(),
other => gpui::div().child(other.to_owned()).into_any_element(),
})
.on_dismiss(cx.listener(|this, _: &bool, _, cx| { this.set_demo_flag("dd-inline", false); cx.notify(); }))
.into_any_element()
} else { gpui::div().into_any_element() },
])An element expression with window: &mut Window and cx: &mut App in scope.
use herogpui::prelude::{Button, Dropdown, MenuItem, Variant, 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![Dropdown::uncontrolled(
"dd-icons-dd",
Button::new("dropdown-icons")
.label("File")
.variant(Variant::Secondary),
vec![
MenuItem::new("new", "New file").icon(icons::PLUS),
MenuItem::new("copy", "Copy").icon(icons::COPY),
MenuItem::new("delete", "Delete")
.icon(icons::CLOSE)
.danger(),
],
)
.id("dropdown-icons-dd")
.into_any_element()])Labels use 14px text with 20px lines; descriptions and section headers use 12px text with 16px lines. Runs in a view's render: self is the view holding this example's state and cx is its Context<Self>.
use herogpui::prelude::{Button, Dropdown, MenuItem, Placement, Variant};
Dropdown::uncontrolled(
"dd-desc-dd",
Button::new("dropdown-desc")
.label("Merge")
.variant(Variant::Secondary),
vec![
MenuItem::new("merge", "Create a merge commit").description(
"All commits from this branch are added to the base branch",
),
MenuItem::new("squash", "Squash and merge")
.description("The commits are combined into one"),
MenuItem::new("rebase", "Rebase and merge")
.description("The commits are rebased onto the base branch"),
],
)
.id("dropdown-desc-dd")
.placement(Placement::BottomStart)An element expression with window: &mut Window and cx: &mut App in scope.
use herogpui::prelude::{Button, Dropdown, MenuItem, Variant};
use herogpui::gpui::SharedString;
let plain = || {
vec![
MenuItem::new("new", "New file"),
MenuItem::new("open", "Open file"),
MenuItem::new("save", "Save"),
]
};
Dropdown::uncontrolled(
"dd-disabled-dd",
Button::new("dropdown-disabled")
.label("Actions")
.variant(Variant::Secondary),
plain(),
)
.id("dropdown-disabled-dd")
.disabled_keys([SharedString::from("save")])An element expression with window: &mut Window and cx: &mut App in scope.
use herogpui::prelude::{Button, Dropdown, MenuItem, Variant};
Dropdown::uncontrolled(
"dd-sections-dd",
Button::new("dropdown-sections")
.label("Actions")
.variant(Variant::Secondary),
vec![
MenuItem::SectionLabel("File".into()),
MenuItem::new("new", "New file"),
MenuItem::new("open", "Open file"),
MenuItem::Separator,
MenuItem::SectionLabel("Danger".into()),
MenuItem::new("delete", "Delete").danger(),
],
)
.id("dropdown-sections-dd")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, Button, Dropdown, MenuItem, Variant};
use herogpui::gpui::prelude::*;
use herogpui::gpui::{App, SharedString, px};
use herogpui::gpui;
let is_open = self.dropdown_open;
let selected = self
.dropdown_selected
.clone()
.unwrap_or_else(|| SharedString::from("none"));
let plain = || {
vec![
MenuItem::new("new", "New file"),
MenuItem::new("open", "Open file"),
MenuItem::new("save", "Save"),
]
};
gpui::div()
.flex()
.flex_col()
.items_start()
.justify_center()
.gap(px(12.))
.children(vec![
Dropdown::new(
"dropdown-controlled-dd",
Button::new("dropdown-controlled")
.label("Actions")
.variant(Variant::Secondary),
plain(),
is_open,
)
.id("dropdown-controlled-dd")
.on_open_change(cx.listener(|this, open: &bool, _, cx| {
this.dropdown_open = *open;
cx.notify();
}))
.on_action(cx.listener(|this, key: &SharedString, _, cx| {
this.dropdown_selected = Some(key.clone());
this.dropdown_open = false;
cx.notify();
}))
.into_any_element(),
para(&format!("Last action: {selected}"), 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::{ActiveTheme, Button, Dropdown, MenuItem, Size, Variant};
use herogpui::gpui::prelude::*;
use herogpui::gpui::{App, px};
use herogpui::gpui;
let is_open = self.dropdown_open;
let plain = || {
vec![
MenuItem::new("new", "New file"),
MenuItem::new("open", "Open file"),
MenuItem::new("save", "Save"),
]
};
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![
Button::new("dropdown-open-btn")
.label(if is_open { "Close menu" } else { "Open menu" })
.size(Size::Sm)
.on_press(cx.listener(|this, _, _, cx| {
this.dropdown_open = !this.dropdown_open;
cx.notify();
}))
.into_any_element(),
para(if is_open { "Open" } else { "Closed" }, cx),
])
.into_any_element(),
Dropdown::new(
"dropdown-open-dd",
Button::new("dropdown-open")
.label("Actions")
.variant(Variant::Secondary),
plain(),
is_open,
)
.id("dropdown-open-dd")
.on_open_change(cx.listener(|this, open: &bool, _, cx| {
this.dropdown_open = *open;
cx.notify();
}))
.into_any_element(),
])Also calls para (included when you copy).
An element expression with window: &mut Window and cx: &mut App in scope.
use herogpui::prelude::{Button, Dropdown, MenuItem, SelectionMode, Variant};
use herogpui::gpui::prelude::*;
use herogpui::gpui::{SharedString, px};
use herogpui::gpui;
gpui::div()
.flex()
.flex_col()
.items_start()
.justify_center()
.gap(px(12.))
.children(vec![Dropdown::uncontrolled(
"dd-single-dd",
Button::new("dropdown-single")
.label("Sort by")
.variant(Variant::Secondary),
vec![
MenuItem::new("name", "Name"),
MenuItem::new("date", "Date"),
MenuItem::new("size", "Size"),
],
)
.id("dropdown-single-dd")
.selection_mode(SelectionMode::Single)
.default_selected_keys([SharedString::from("date")])
.into_any_element()])An element expression with window: &mut Window and cx: &mut App in scope.
use herogpui::prelude::{Button, Dropdown, IndicatorKind, MenuItem, SelectionMode, Variant};
use herogpui::gpui::SharedString;
Dropdown::uncontrolled(
"dd-single-ind-dd",
Button::new("dropdown-single-ind")
.label("Sort by")
.variant(Variant::Secondary),
vec![
MenuItem::new("name", "Name"),
MenuItem::new("date", "Date"),
],
)
.id("dropdown-single-ind-dd")
.selection_mode(SelectionMode::Single)
.default_selected_keys([SharedString::from("name")])
.indicator(IndicatorKind::Dot)The composed Dropdown forwards item and indicator render state into the live menu. Open it and choose rows to watch the selection move. Runs in a view's render: self is the view holding this example's state and cx is its Context<Self>.
use herogpui::prelude::{Button, Dropdown, MenuItem, SelectionMode, Variant};
use herogpui::gpui::prelude::*;
use herogpui::gpui::{SharedString, px};
use herogpui::gpui;
let selected = self
.dropdown_selected
.clone()
.unwrap_or_else(|| SharedString::from("none"));
gpui::div()
.flex()
.flex_col()
.items_start()
.justify_center()
.gap(px(12.))
.children(vec![
Dropdown::uncontrolled(
"dd-render-props-dd",
Button::new("dropdown-render-props")
.label("Render state")
.variant(Variant::Secondary),
vec![
MenuItem::new("name", "Name"),
MenuItem::new("date", "Date"),
MenuItem::new("size", "Size"),
],
)
.selection_mode(SelectionMode::Multiple)
.default_selected_keys([SharedString::from("name")])
.item_content(|key, state| {
gpui::div()
.child(format!(
"{key}: {}",
if state.is_selected {
"selected"
} else {
"idle"
}
))
.into_any_element()
})
.indicator_content(|_, selected, _| {
gpui::div()
.w(px(16.))
.child(if selected { "✓" } else { "" })
.into_any_element()
})
.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::{Button, Dropdown, MenuItem, SelectionMode, Variant};
use herogpui::gpui::prelude::*;
use herogpui::gpui::{SharedString, px};
use herogpui::gpui;
let dd_multi = self.dropdown_multi.clone();
gpui::div()
.flex()
.flex_col()
.items_start()
.justify_center()
.gap(px(12.))
.children(vec![Dropdown::uncontrolled(
"dd-section-sel-dd",
Button::new("dropdown-section-sel")
.label("View")
.variant(Variant::Secondary),
vec![
MenuItem::SectionLabel("Sort".into()),
MenuItem::new("name", "Name"),
MenuItem::new("date", "Date"),
MenuItem::Separator,
MenuItem::SectionLabel("Show".into()),
MenuItem::new("hidden", "Hidden files"),
],
)
.id("dropdown-section-sel-dd")
.selection_mode(SelectionMode::Multiple)
.selected_keys(dd_multi)
.on_selection_change(cx.listener(|this, keys: &[SharedString], _, cx| {
this.dropdown_multi = keys.to_vec();
cx.notify();
}))
.into_any_element()])An element expression with window: &mut Window and cx: &mut App in scope.
use herogpui::prelude::{Button, Dropdown, MenuItem, Variant};
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![Dropdown::uncontrolled(
"dd-shortcuts-dd",
Button::new("dropdown-shortcuts")
.label("Edit")
.variant(Variant::Secondary),
vec![
MenuItem::new("cut", "Cut").shortcut("Ctrl X"),
MenuItem::new("copy", "Copy").shortcut("Ctrl C"),
MenuItem::new("paste", "Paste").shortcut("Ctrl V"),
],
)
.id("dropdown-shortcuts-dd")
.into_any_element()])An element expression with window: &mut Window and cx: &mut App in scope.
use herogpui::prelude::{Avatar, Dropdown, MenuItem};
Dropdown::uncontrolled(
"Jane Doe-dd",
Avatar::new("dropdown-trigger-avatar").name("Jane Doe"),
vec![
MenuItem::new("profile", "Profile"),
MenuItem::new("settings", "Settings"),
MenuItem::Separator,
MenuItem::new("logout", "Log out").danger(),
],
)
.id("Jane Doe-dd")Hold the button for half a second. An element expression with window: &mut Window and cx: &mut App in scope.
use herogpui::prelude::{Button, Dropdown, DropdownTrigger, MenuItem, Variant};
use herogpui::gpui::prelude::*;
use herogpui::gpui::px;
use herogpui::gpui;
let plain = || {
vec![
MenuItem::new("new", "New file"),
MenuItem::new("open", "Open file"),
MenuItem::new("save", "Save"),
]
};
gpui::div()
.flex()
.flex_col()
.items_start()
.justify_center()
.gap(px(12.))
.children(vec![
Dropdown::uncontrolled(
"dd-long-dd",
Button::new("dropdown-long")
.label("Long press")
.variant(Variant::Secondary),
plain(),
)
.id("dropdown-long-dd")
.trigger(DropdownTrigger::LongPress)
.into_any_element(),
])The plainest action menu: `on_action` receives the chosen key, and a danger item renders in the danger palette. 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, Button, Dropdown, MenuItem, Variant};
use herogpui::gpui::prelude::*;
use herogpui::gpui::{App, SharedString, px};
use herogpui::gpui;
gpui::div()
.flex()
.flex_col()
.items_start()
.justify_center()
.gap(px(12.))
.children(vec![
Dropdown::uncontrolled(
"dd-basic-dd",
Button::new("dropdown-basic")
.label("Actions")
.variant(Variant::Secondary),
vec![
MenuItem::new("new-file", "New file"),
MenuItem::new("open-file", "Open file"),
MenuItem::new("delete-file", "Delete file").danger(),
],
)
.id("dropdown-basic-dd")
.on_action(cx.listener(|this, key: &SharedString, _, cx| {
this.dropdown_last_basic = key.clone();
cx.notify();
}))
.into_any_element(),
para(
&format!("Last action: {}", self.dropdown_last_basic),
cx,
),
])Also calls para (included when you copy).
The selected keys live in the caller and are fed back through `selected_keys`; the caption reads the same set the menu renders. 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, Button, Dropdown, MenuItem, SelectionMode, Variant};
use herogpui::gpui::prelude::*;
use herogpui::gpui::{App, SharedString, px};
use herogpui::gpui;
gpui::div()
.flex()
.flex_col()
.items_start()
.justify_center()
.gap(px(12.))
.children(vec![
Dropdown::new(
"dropdown-controlled-sel-dd",
Button::new("dropdown-controlled-sel")
.label("Formatting")
.variant(Variant::Secondary),
vec![
MenuItem::new("bold", "Bold"),
MenuItem::new("italic", "Italic"),
],
self.dropdown_open,
)
.id("dropdown-controlled-sel-dd")
.selection_mode(SelectionMode::Multiple)
.selected_keys(self.dropdown_doc_marks.clone())
.on_selection_change(cx.listener(|this, keys: &[SharedString], _, cx| {
this.dropdown_doc_marks = keys.to_vec();
cx.notify();
}))
.on_open_change(cx.listener(|this, open: &bool, _, cx| {
this.dropdown_open = *open;
cx.notify();
}))
.into_any_element(),
para(
&format!(
"Active: {}",
if self.dropdown_doc_marks.is_empty() {
"none".to_owned()
} else {
self.dropdown_doc_marks
.iter()
.map(|k| k.as_ref())
.collect::<Vec<_>>()
.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::{ActiveTheme, Button, Dropdown, MenuItem, SelectionMode, Variant};
use herogpui::gpui::prelude::*;
use herogpui::gpui::{App, SharedString, px};
use herogpui::gpui;
gpui::div()
.flex()
.flex_col()
.items_start()
.justify_center()
.gap(px(12.))
.children(vec![
Dropdown::new(
"dropdown-multi-dd",
Button::new("dropdown-multi-trigger")
.label("Columns")
.variant(Variant::Secondary),
vec![
MenuItem::new("name", "Name"),
MenuItem::new("role", "Role"),
MenuItem::new("status", "Status"),
],
self.dropdown_open,
)
.id("dropdown-multi-trigger-dd")
.selection_mode(SelectionMode::Multiple)
.selected_keys(self.dropdown_multi.clone())
.disabled_keys(vec!["status"])
.on_selection_change(cx.listener(|this, keys: &[SharedString], _, cx| {
this.dropdown_multi = keys.to_vec();
cx.notify();
}))
.on_open_change(cx.listener(|this, open: &bool, _, cx| {
this.dropdown_open = *open;
cx.notify();
}))
.into_any_element(),
para(
&format!("Showing {} columns", self.dropdown_multi.len()),
cx,
),
])Also calls para (included when you copy).
Also calls para (included when you copy).
Also calls para (included when you copy).
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
Dropdown 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 Dropdown 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
| Method | Values | Description |
|---|---|---|
placement(DropdownPlacement) | PopoverPlacement | Placement relative to the measured trigger. All 22 union placements flip to the side with more room when the preferred side cannot fit, keeping a 12px cross-axis viewport inset with the scroller capped to the available height. |
// 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: 36 entries ported, 11 partial, 14 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 |
|---|---|---|---|
is_open( | true | | — | Sets the open state of the menu (controlled). |
default_open( | true | | — | Sets the default open state of the menu (uncontrolled). |
on_open_change( | Fn( | — | Handler called when the open state changes. |
trigger( | DropdownTrigger:: | DropdownTrigger:: | The type of interaction that triggers the menu. |
new(Partial | AnyElement | — | Dropdown content. |
placement( | PopoverPlacement | DropdownPlacement:: | Placement relative to the measured trigger. All 22 union placements flip to the side with more room when the preferred side cannot fit, keeping a 12px cross-axis viewport inset with the scroller capped to the available height. |
selection_mode( | SelectionMode:: | SelectionMode:: | Whether single or multiple selection is enabled. |
selected_keys( | iterable of keys | — | The currently selected keys (controlled). |
default_selected_keys( | iterable of keys | — | The initial selected keys (uncontrolled). |
on_selection_change( | Fn( | — | Handler called when the selection changes. |
disabled_keys( | iterable of keys | — | Keys of disabled items. |
on_action( | Fn( | — | Handler called when an item is activated. |
new( | AnyElement | — | Menu content. |
SectionLabel + itemsPartial | AnyElement | — | Section content. |
new( | Key | — | Unique identifier for the item. |
danger(Partial | 'default' | | "default" | Visual variant of the item. |
item_content( | AnyElement | | — | Item content or a render function. |
indicator( | IndicatorKind:: | IndicatorKind:: | Type of selection indicator to display. |
indicator_content( | AnyElement | | — | Custom indicator content or render function. |
item_content( | true | | — | Render-function state: whether the item is selected. |
item_content( | true | | — | Render-function state: whether the item has focus. |
item_content( | true | | — | Render-function state: whether the item is disabled. |
item_content( | true | | — | Render-function state: whether the item is being pressed. |
submenu(Partial | AnyElement | — | Custom submenu indicator content. |
Not ported14 HeroUI entries not ported
| HeroUI v3 | Why it is not ported |
|---|---|
Dropdown.className | |
Dropdown.Trigger.className | For the trigger. |
Dropdown.Popover.className | For the popover. |
Dropdown.Menu.className | For the menu. Standalone Menu provides panel sizing, row metrics, panel_gap and panel_padding builders; sx styles its outer wrapper. |
Dropdown.Section.selectionMode | Selection mode for items within this section. |
Dropdown.Section.selectedKeys | The currently selected keys (controlled). |
Dropdown.Section.defaultSelectedKeys | The initial selected keys (uncontrolled). |
Dropdown.Section.onSelectionChange | Handler called when section selection changes. |
Dropdown.Section.disabledKeys | Keys of disabled items in the section. |
Dropdown.Section.className | For the section. |
Dropdown.Item.className | For the item. |
Dropdown.ItemIndicator.className | For the indicator. |
Dropdown.SubmenuIndicator.className | For the submenu indicator. |
Dropdown.SubmenuTrigger.className | For the submenu trigger. |
Parts
| Part | Description |
|---|---|
Dropdown | MenuTrigger wrapper that owns open state and composes the trigger and popover. |
Dropdown | Button or custom element that opens the menu. |
Dropdown | Floating panel positioned relative to the trigger. |
Menu | Scrollable menu container and selection owner. |
MenuPartial | Grouped menu items with an optional header. |
MenuItem | Focusable action or selectable menu row; descriptions wrap within the popover width. |
Menu | Checkmark or dot selection marker. |
MenuItemPartial | Trailing chevron for an item that opens a submenu. |
MenuItemPartial | Item wrapper that keeps the parent open while opening a child popover. |
States
| State | Builder | Description |
|---|---|---|
Hovered | track_interaction | Pointer is over the trigger or a menu item. |
Focused | FocusHandle | Element owns keyboard focus. |
Focus visible | focus_handle | Keyboard focus indicator is visible. |
Pressed | track_interaction | Trigger or item is being activated. |
Disabled | disabled_keys | Trigger or item cannot be activated. |
Selected | selected_keys | Item is selected in single or multiple mode. |
Entering | overlay_phase::Entering | Popover is playing its enter transition. |
Exiting | overlay_phase::Exiting | Popover remains mounted while its exit transition plays. |