Menu

Menu is the popup action list used by higher-level controls such as MenuButton and Select.
It takes a list of MenuItem values and renders them as vertically stacked ghost buttons inside a bordered, elevated surface. When the content grows tall enough, the menu becomes scrollable.

Example

use fission::prelude::*;

let widget: Widget = Menu {
items: vec![
    MenuItem {
        label: "Archive".into(),
        icon: None,
        on_select: Some(archive_action),
    },
    MenuItem {
        label: "Mark unread".into(),
        icon: None,
        on_select: Some(mark_unread_action),
    },
],
width: Some(220.0),
max_height: Some(280.0),
}
.into();
Menu itself only renders the list. Some surrounding widget still has to decide when and where to show it.

Field table

Field
Type
Meaning
Notes / default behavior
items
Vec<MenuItem>
Entries to render from top to bottom.
Required.
width
Option<f32>
Target menu width.
If None, item rows default to 200.0 wide.
max_height
Option<f32>
Maximum height before the menu scrolls.
Defaults to 300.0.

Layout and interaction behavior

Each item row is rendered as a ghost button aligned to the start, with dividers between rows. The menu surface itself is wrapped in a Scroll when the estimated content height exceeds the configured maximum. This is why Menu is a good building block for compact action lists but not for enormous data sets.
Menu also does not own open state. Whether it appears, disappears, or repositions belongs to the parent widget or portal.

Specific advice

Use Menu for short action lists. If the content is actually a form field choice, Select often gives better product-level meaning. If the content is long, searchable, or remote-backed, a Combobox or a dedicated screen is usually easier to use.

Production checklist

For Menu, review the fields that change behavior before treating the widget as finished: items, width, max_height. The goal is to make the product rule visible in state and actions, not hidden inside ad-hoc construction code.
If this widget appears inside an interactive flow, keep the surrounding action binding in the parent component and test that the flow still has one clear reducer path.
When child widgets are generated from data, give reordered or filtered rows an explicit WidgetId so retained local state and scroll behavior do not drift between items.
Check the semantics tree for the user-facing label or role that makes this widget understandable without relying only on pixels.
Prefer parent layout and design-system sizing first; use explicit size or spacing fields when the product layout requires that constraint on this widget specifically.
Add at least one component or harness test that confirms the visible text, semantic role, action dispatch, and layout constraint that matter for this widget in context.
If a screen starts repeating the same Menu setup, extract a named component around this widget. That keeps the reference API small while making product code easier to read and safer for generated code to copy.
MenuButton, MenuItem, Select, and Scroll.
Fission
A cross-platform, GPU-accelerated user interface framework for Rust. MIT licensed.
Copyright (c) 2026 Fission
Ready to use today. Widget APIs are expected to remain stable; some runtime and shell APIs may change before 1.0.0.
Fission 0.7.0