Menu
A dropdown of actions on the Popover API: the panel is in the top layer, so nothing clips it, and it opens and closes without script. Arrow keys, Home and End move between items; on a narrow screen it is a sheet along the bottom.
With a label
A text trigger with a chevron, lined up with the trigger's left edge.
<div class="pb-24">
<%= menu "Options", align: :start do |menu| %>
<% menu.link "Go to toasts", component_path("toast") %>
<% menu.link "Go to dialogs", component_path("dialog") %>
<% end %>
</div>Icon trigger with actions
With no label the trigger is a ⋮ button. Items can be button_to actions, and tone: :danger pairs with a confirm.
This example talks to a server
These are static pages, so what this example saves, posts or searches for won't answer here. Run the browser
(
bin/dev) or mount it in an app to try it for real.
<div class="pb-28">
<%= menu do |menu| %>
<% menu.button "Send a toast", stream_toast_path, params: { tone: "good", message: "Sent from a menu." } %>
<% menu.divider %>
<% menu.button "Delete", stream_toast_path, tone: :danger,
params: { tone: "bad", message: "Deleted (not really)." },
form: { data: { turbo_confirm: "Delete this thing?", turbo_confirm_accept: "Delete",
turbo_confirm_variant: "danger" } } %>
<% end %>
</div>Sections, icons and a disclosure
section heads the items after it; icon: leads a label; item is a plain button for wiring; disclosure folds a small form out in place, so the whole exchange happens inside the panel.
<%= menu "Organise", align: :start do |menu| %>
<% menu.section "Share" %>
<% menu.link "Copy link", "#", icon: :copy %>
<% menu.item "Rename", icon: :pencil %>
<% menu.disclosure "Move to…", icon: :folder do %>
<%= form_with url: "#", method: :get, class: "flex flex-col gap-2" do |form| %>
<%= form.text_field :folder, placeholder: "Folder name", class: control_classes(:input, size: :small), "aria-label": "Folder name" %>
<%= button "Move", :primary, size: :small, type: "submit" %>
<% end %>
<% end %>
<% menu.divider %>
<% menu.section "Danger" %>
<% menu.button "Delete", "#", method: :delete, tone: :danger, icon: :x, form: { data: { turbo_confirm: "Delete it?" } } %>
<% end %>