日本語

Menu

A menu of actions opened by a button.

Result

menu.rs
use hypersig::html::{div, p};
use hypersig::style::pattern::stack;
use hypersig::style::value::rem;
use hypersig::{Page, Signals};
use hypersig_ui::{ButtonSize, ButtonVariant, Menu, MenuItem};
use serde::{Deserialize, Serialize};

#[derive(Signals, Serialize, Deserialize)]
pub struct Project {
    archived: bool,
    status: String,
}

const ACTIONS: Menu<Project> = Menu::new("actions");

pub fn page() -> Page<Project> {
    let archived = Project::archived();
    let status = Project::status();
    let initial = Project {
        archived: false,
        status: String::new(),
    };
    Page::new(
        "Project",
        initial,
    )
    .child(
        div()
            .css(stack(rem(1)))
            .child(
                div()
                    .child(
                        ACTIONS
                            .trigger(ButtonVariant::Outline, ButtonSize::Default)
                            .text("Project actions"),
                    )
                    .child(
                        ACTIONS.menu([
                            MenuItem::new(
                                "Rename",
                                status.set("Renamed the project."),
                            ),
                            MenuItem::new(
                                "Duplicate",
                                status.set("Duplicated the project."),
                            ),
                            MenuItem::new(
                                "Archive",
                                archived.set(true).then(status.set("Archived the project.")),
                            )
                            .disabled(archived),
                            MenuItem::new(
                                "Delete",
                                status.set("Deleted the project."),
                            )
                            .destructive(),
                        ]),
                    ),
            )
            .child(p().attr("role", "status").bind_text(status)),
    )
}

Accessibility

It follows the WAI-ARIA menu button pattern. The button has aria-haspopup="menu", the menu role="menu", and each action role="menuitem". The menu is a popover, so the browser shows it over the page and closes it on Escape or on a click outside. It is placed under the button with CSS anchor positioning and moves above it where there is no room below.

A disabled action keeps its place, and the arrow keys skip it.

KeyWhat it does
Enter, SpaceWith focus on the button, opens the menu and moves focus to the first action. With focus on an action, runs it and closes the menu.
Up, DownMove to the previous or next action.
Home, EndMove to the first or last action.
EscapeCloses the menu and returns focus to the button.
TabCloses the menu.

API

ItemSummary
Menu::newA menu whose id is name.
triggerThe button that opens and closes the menu.
menuThe menu, holding items in order.
MenuItem::newAn action labeled label that runs run when chosen.
destructiveDraws the action in token::destructive. It is for an action that deletes.
disabledDisables the action while when is true, which the arrow keys then skip.