Dropdown Menu
Displays a menu to the user triggered by a button with a list of actions or functions.
Installation
Add the component to your project:
rails generate shadcn:component dropdown_menu
Usage
<%= render Shadcn::DropdownMenuComponent.new do |menu| %>
<% menu.with_trigger do %>
<%= render Shadcn::ButtonComponent.new(variant: :outline) { "Open Menu" } %>
<% end %>
<% menu.with_menu do |content| %>
<% content.with_label { "My Account" } %>
<% content.with_separator %>
<% content.with_item(href: "/profile") { "Profile" } %>
<% content.with_item(href: "/settings") { "Settings" } %>
<% content.with_separator %>
<% content.with_item(variant: :destructive) { "Log out" } %>
<% end %>
<% end %>
Examples
Basic
<%= render Shadcn::DropdownMenuComponent.new do |menu| %>
<% menu.with_trigger do %>
<%= render Shadcn::ButtonComponent.new(variant: :outline) { "Options" } %>
<% end %>
<% menu.with_menu do |content| %>
<% content.with_item(href: "#") { "Edit" } %>
<% content.with_item(href: "#") { "Duplicate" } %>
<% content.with_item(href: "#") { "Archive" } %>
<% end %>
<% end %>
With Icons
Add icons to menu items for better visual clarity.
<%= render Shadcn::DropdownMenuComponent.new do |menu| %>
<% menu.with_trigger do %>
<%= render Shadcn::ButtonComponent.new(variant: :outline) { "Actions" } %>
<% end %>
<% menu.with_menu do |content| %>
<% content.with_item(href: "#") do %>
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M17 3a2.85 2.83 0 1 1 4 4L7.5 20.5 2 22l1.5-5.5Z"/><path d="m15 5 4 4"/></svg>
Edit
<% end %>
<% content.with_item(href: "#") do %>
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect width="14" height="14" x="8" y="8" rx="2" ry="2"/><path d="M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2"/></svg>
Copy
<% end %>
<% content.with_item(href: "#") do %>
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M21.174 6.812a1 1 0 0 0-3.986-3.987L3.842 16.174a2 2 0 0 0-.5.83l-1.321 4.352a.5.5 0 0 0 .623.622l4.353-1.32a2 2 0 0 0 .83-.497z"/><path d="m15 5 4 4"/></svg>
Share
<% end %>
<% end %>
<% end %>
With Separators and Labels
Use separators and labels to organize menu items into logical groups.
<%= render Shadcn::DropdownMenuComponent.new do |menu| %>
<% menu.with_trigger do %>
<%= render Shadcn::ButtonComponent.new(variant: :outline) { "Settings" } %>
<% end %>
<% menu.with_menu do |content| %>
<% content.with_label { "Account" } %>
<% content.with_separator %>
<% content.with_item(href: "#") { "Profile" } %>
<% content.with_item(href: "#") { "Billing" } %>
<% content.with_item(href: "#") { "Notifications" } %>
<% content.with_separator %>
<% content.with_label { "Danger Zone" } %>
<% content.with_separator %>
<% content.with_item(variant: :destructive, href: "#") { "Delete Account" } %>
<% end %>
<% end %>
With Keyboard Shortcuts
Display keyboard shortcuts to help users discover shortcuts.
<%= render Shadcn::DropdownMenuComponent.new do |menu| %>
<% menu.with_trigger do %>
<%= render Shadcn::ButtonComponent.new(variant: :outline) { "File" } %>
<% end %>
<% menu.with_menu do |content| %>
<% content.with_item(href: "#") do |item| %>
New File
<% item.with_shortcut { "⌘N" } %>
<% end %>
<% content.with_item(href: "#") do |item| %>
Open
<% item.with_shortcut { "⌘O" } %>
<% end %>
<% content.with_item(href: "#") do |item| %>
Save
<% item.with_shortcut { "⌘S" } %>
<% end %>
<% content.with_separator %>
<% content.with_item(href: "#") do |item| %>
Print
<% item.with_shortcut { "⌘P" } %>
<% end %>
<% end %>
<% end %>
Destructive Items
Use the destructive variant for dangerous actions.
<%= render Shadcn::DropdownMenuComponent.new do |menu| %>
<% menu.with_trigger do %>
<%= render Shadcn::ButtonComponent.new(variant: :outline) { "Manage" } %>
<% end %>
<% menu.with_menu do |content| %>
<% content.with_item(href: "#") { "View Details" } %>
<% content.with_item(href: "#") { "Edit" } %>
<% content.with_separator %>
<% content.with_item(variant: :destructive, href: "#") { "Delete" } %>
<% end %>
<% end %>
Disabled Items
Disable menu items when an action is unavailable.
<%= render Shadcn::DropdownMenuComponent.new do |menu| %>
<% menu.with_trigger do %>
<%= render Shadcn::ButtonComponent.new(variant: :outline) { "Options" } %>
<% end %>
<% menu.with_menu do |content| %>
<% content.with_item(href: "#") { "Edit" } %>
<% content.with_item(href: "#", disabled: true) { "Share (Coming Soon)" } %>
<% content.with_item(href: "#") { "Duplicate" } %>
<% end %>
<% end %>
Inset Items
Use the inset prop to add left padding for better alignment with icons.
<%= render Shadcn::DropdownMenuComponent.new do |menu| %>
<% menu.with_trigger do %>
<%= render Shadcn::ButtonComponent.new(variant: :outline) { "Menu with Icons" } %>
<% end %>
<% menu.with_menu do |content| %>
<% content.with_label(inset: true) { "Actions" } %>
<% content.with_separator %>
<% content.with_item(href: "#", inset: true) do %>
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M17 3a2.85 2.83 0 1 1 4 4L7.5 20.5 2 22l1.5-5.5Z"/></svg>
Edit
<% end %>
<% content.with_item(href: "#", inset: true) { "Delete (no icon)" } %>
<% end %>
<% end %>
Alignment
Control the alignment of the dropdown menu content relative to the trigger.
<!-- Align to start (left) -->
<%= render Shadcn::DropdownMenuComponent.new(align: :start) do |menu| %>
<% menu.with_trigger do %>
<%= render Shadcn::ButtonComponent.new(variant: :outline) { "Align Start" } %>
<% end %>
<% menu.with_menu do |content| %>
<% content.with_item(href: "#") { "Item 1" } %>
<% content.with_item(href: "#") { "Item 2" } %>
<% end %>
<% end %>
<!-- Align to center -->
<%= render Shadcn::DropdownMenuComponent.new(align: :center) do |menu| %>
<% menu.with_trigger do %>
<%= render Shadcn::ButtonComponent.new(variant: :outline) { "Align Center" } %>
<% end %>
<% menu.with_menu do |content| %>
<% content.with_item(href: "#") { "Item 1" } %>
<% content.with_item(href: "#") { "Item 2" } %>
<% end %>
<% end %>
<!-- Align to end (right) - default -->
<%= render Shadcn::DropdownMenuComponent.new(align: :end) do |menu| %>
<% menu.with_trigger do %>
<%= render Shadcn::ButtonComponent.new(variant: :outline) { "Align End" } %>
<% end %>
<% menu.with_menu do |content| %>
<% content.with_item(href: "#") { "Item 1" } %>
<% content.with_item(href: "#") { "Item 2" } %>
<% end %>
<% end %>
API Reference
DropdownMenuComponent
API Reference
| Prop | Type | Default | Description |
|---|---|---|---|
| open |
Boolean
|
false
|
Whether the dropdown starts in open state |
| align |
Symbol
|
:end
|
Content alignment (:start, :center, :end) |
| side |
Symbol
|
:bottom
|
Side to show content (:top, :right, :bottom, :left) |
Slots
| Slot | Description |
|---|---|
| with_trigger | The element that opens the dropdown (usually a button) |
| with_menu | The dropdown menu content container (yields DropdownMenuContentComponent) |
DropdownMenuContentComponent Slots
| Slot | Props | Description |
|---|---|---|
| with_item | href:, variant:, disabled:, inset: |
Menu item (can be a link or div) |
| with_label | inset: |
Section label for grouping items |
| with_separator | - | Visual separator between menu sections |
| with_group | - | Group of related items |
DropdownMenuItemComponent
API Reference
| Prop | Type | Default | Description |
|---|---|---|---|
| href |
String
|
nil
|
Link URL (renders as <a> if provided, <div> otherwise) |
| variant |
Symbol
|
:default
|
Item variant (:default, :destructive) |
| disabled |
Boolean
|
false
|
Whether the item is disabled |
| inset |
Boolean
|
false
|
Whether to add left padding for icon alignment |
DropdownMenuItemComponent Slots
| Slot | Description |
|---|---|
| with_shortcut | Keyboard shortcut hint displayed on the right |
Stimulus Controller
This component requires JavaScript. The Stimulus controller shadcn--dropdown provides interactivity.
Manages dropdown menu open/close state, positioning, keyboard navigation, and item selection.
Installation
Add to your config/importmap.rb:
pin "shadcn-rails", to: "shadcn/index.js"
Then in your app/javascript/controllers/index.js:
import { Application } from "@hotwired/stimulus"
import { registerShadcnControllers } from "shadcn-rails"
const application = Application.start()
registerShadcnControllers(application)
Install the package:
npm install shadcn-rails
Then in your app/javascript/controllers/index.js:
import { Application } from "@hotwired/stimulus"
import { registerShadcnControllers } from "shadcn-rails"
const application = Application.start()
registerShadcnControllers(application)
Install the package:
yarn add shadcn-rails
Then in your app/javascript/controllers/index.js:
import { Application } from "@hotwired/stimulus"
import { registerShadcnControllers } from "shadcn-rails"
const application = Application.start()
registerShadcnControllers(application)
Install the package:
npm install shadcn-rails
Then in your app/javascript/controllers/index.js:
import { Application } from "@hotwired/stimulus"
import { registerShadcnControllers } from "shadcn-rails"
const application = Application.start()
registerShadcnControllers(application)
Or import just this controller:
import DropdownController from "shadcn-rails/controllers/dropdown_controller"
application.register("shadcn--dropdown", DropdownController)
Targets
| Name | Description |
|---|---|
| trigger | The element that triggers the dropdown to open |
| content | The dropdown menu content container |
| item | Individual menu items for keyboard navigation |
Values
| Name | Type | Default | Description |
|---|---|---|---|
| open | Boolean |
false |
Current open/closed state |
| align | String |
end |
Content alignment (start, center, end) |
| side | String |
bottom |
Side to show content (top, bottom, left, right) |
Actions
| Action | Description |
|---|---|
| toggle | Toggles the dropdown open/closed state |
| show | Opens the dropdown menu |
| hide | Closes the dropdown menu |
| close | Alias for hide |
| selectItem | Handles item selection and closes menu |
TypeScript
Type definitions are included. Import types as needed:
import type { DropdownController } from "shadcn-rails"
Accessibility
- Uses
role="menu"for the dropdown content - Sets
role="menuitem"on each item - Sets
aria-expandedon trigger to indicate open state - Supports full keyboard navigation:
- Escape - Closes the menu and returns focus to trigger
- ↓ / ↑ - Navigate through menu items
- Home / End - Jump to first/last item
- Enter / Space - Select focused item
- Disabled items use
data-disabledattribute and are skipped in keyboard navigation - Automatically closes when clicking outside the dropdown
- Focus is automatically moved to the first menu item when opened
On This Page