Skip to main content
Gremorie
Overlays

Dropdown Menu

Menu de ações liderado por verbos, atrelado a um trigger. Itens, grupos, separadores, itens de checkbox ou radio, submenus e dicas de shortcut alinhadas à direita.

Visão geral

DropdownMenu é o primitivo certo para ações: Edit, Delete, Duplicate, Open in new tab. É distinto do Select, que guarda valores (USA, Brazil, Japan). Quando os itens do menu se leem como verbos, este é o primitivo certo.

O compound expõe tudo o que o Radix oferece: itens com variante destructive, itens de checkbox e radio com indicadores auto-renderizados, seções agrupadas, separadores, submenus e um helper de shortcut que alinha o texto à direita.

Preview

'use client';import { Button } from '@gremorie/rx-forms';import {  DropdownMenu,  DropdownMenuContent,  DropdownMenuItem,  DropdownMenuLabel,  DropdownMenuSeparator,  DropdownMenuTrigger,} from '@gremorie/rx-overlays';export function DropdownMenuPreview() {  return (    <DropdownMenu>      <DropdownMenuTrigger asChild>        <Button variant="outline">Actions</Button>      </DropdownMenuTrigger>      <DropdownMenuContent>        <DropdownMenuLabel>Actions</DropdownMenuLabel>        <DropdownMenuSeparator />        <DropdownMenuItem>Open in chat</DropdownMenuItem>        <DropdownMenuItem>Copy URL</DropdownMenuItem>        <DropdownMenuItem>Export</DropdownMenuItem>      </DropdownMenuContent>    </DropdownMenu>  );}

Anatomia

DropdownMenu                       Raiz que mantém o estado de abertura
├─ DropdownMenuTrigger             Elemento que abre o menu
└─ DropdownMenuContent             Superfície em portal (sideOffset default 4)
   ├─ DropdownMenuLabel            Rótulo de seção não interativo
   ├─ DropdownMenuSeparator        Divisor
   ├─ DropdownMenuGroup            Agrupa itens relacionados
   │  └─ DropdownMenuItem          Linha de ação (variant default | destructive, inset)
   ├─ DropdownMenuCheckboxItem     Item alternável
   ├─ DropdownMenuRadioGroup       Container de escolha única
   │  └─ DropdownMenuRadioItem     Item de escolha única
   ├─ DropdownMenuSub              Submenu aninhado
   │  ├─ DropdownMenuSubTrigger    Abre o submenu
   │  └─ DropdownMenuSubContent    Superfície do submenu
   └─ DropdownMenuShortcut         Dica de teclado alinhada à direita

Instalação

bash npx gremorie@latest add rx-dropdown-menu

bash pnpm dlx gremorie@latest add rx-dropdown-menu

bash yarn dlx gremorie@latest add rx-dropdown-menu

bash bunx --bun gremorie@latest add rx-dropdown-menu

Uso

import { Button } from "@gremorie/rx-forms";
import {
  DropdownMenu,
  DropdownMenuContent,
  DropdownMenuItem,
  DropdownMenuLabel,
  DropdownMenuSeparator,
  DropdownMenuTrigger,
} from "@gremorie/rx-overlays";

export function Example() {
  return (
    <DropdownMenu>
      <DropdownMenuTrigger asChild>
        <Button variant="outline">Actions</Button>
      </DropdownMenuTrigger>
      <DropdownMenuContent>
        <DropdownMenuLabel>Actions</DropdownMenuLabel>
        <DropdownMenuSeparator />
        <DropdownMenuItem>Open in chat</DropdownMenuItem>
        <DropdownMenuItem>Copy URL</DropdownMenuItem>
        <DropdownMenuItem>Export</DropdownMenuItem>
      </DropdownMenuContent>
    </DropdownMenu>
  );
}

A edição Angular deste componente hoje é distribuída a partir do source (veja o workbench para o lado a lado); a entrada no registry vem a seguir.

API

Estende o Radix DropdownMenu.Root. API controlada padrão (open, defaultOpen, onOpenChange, modal).

Estende o Radix DropdownMenu.Trigger. Use asChild para encaminhar estilos a um Button ou qualquer trigger customizado.

PropTypeDefaultDescription
sideOffsetnumber4Espaçamento em pixels entre trigger e content.
side"top" | "right" | "bottom" | "left""bottom"Lado preferido; vira automaticamente.
align"start" | "center" | "end""center"Alinhamento relativo ao eixo do trigger.

Envolvido em um Portal do Radix. Limitado a --radix-dropdown-menu-content-available-height, com scroll, min-w-[8rem].

PropTypeDefaultDescription
insetbooleanfalseAdiciona pl-8 para o item alinhar com as linhas de checkbox/radio.
variant"default" | "destructive""default"destructive troca a cor do texto e do ícone para o token destructive.
disabledbooleanfalseDesabilita a interação; renderiza a 50% de opacidade.
PropTypeDefaultDescription
checkedboolean | "indeterminate"-Estado checked controlado.
onCheckedChange(checked: boolean) => void-Disparado ao alternar.

Renderiza um ícone de check posicionado de forma absoluta à esquerda quando marcado.

Emparelhe um grupo com um ou mais itens de radio. O grupo detém o value e o onValueChange. Cada item de radio renderiza um bullet auto-posicionado quando selecionado.

Heading de seção não interativo.

PropTypeDefaultDescription
insetbooleanfalseAdiciona pl-8 para alinhar com as linhas de check/radio.

Divisor fino bg-border com margem negativa para abranger o padding do menu.

Um <span> alinhado à direita para dicas de teclado (⌘C, ⇧⌫). Helper de layout puro; sem lógica Radix.

Submenu aninhado. O sub-trigger renderiza um chevron auto-posicionado à direita. O sub-content abre ao lado do trigger.

Pass-throughs sobre os primitivos do Radix com atributos data-slot.

Composição

  1. <DropdownMenu> detém o estado de aberto/fechado.
  2. <DropdownMenuTrigger asChild> envolve um Button ou botão de ícone.
  3. <DropdownMenuContent> monta via Portal ancorado ao trigger.
  4. Dentro do content: agrupe itens com DropdownMenuGroup, rotule seções com DropdownMenuLabel, divida com DropdownMenuSeparator.
  5. Shortcuts ficam na borda direita via DropdownMenuShortcut.
  6. Submenus envolvem blocos aninhados de DropdownMenuSub.

Variações

O menu canônico de ações de linha: shortcuts alinhados à direita, um DropdownMenuSub aninhado e a variante destructive para delete.

'use client';import {  CopyIcon,  MoreHorizontalIcon,  PencilIcon,  Trash2Icon,} from 'lucide-react';import { Button } from '@gremorie/rx-forms';import {  DropdownMenu,  DropdownMenuContent,  DropdownMenuItem,  DropdownMenuSeparator,  DropdownMenuShortcut,  DropdownMenuSub,  DropdownMenuSubContent,  DropdownMenuSubTrigger,  DropdownMenuTrigger,} from '@gremorie/rx-overlays';export function DropdownMenuSubmenuPreview() {  return (    <DropdownMenu>      <DropdownMenuTrigger asChild>        <Button variant="ghost" size="icon" aria-label="Row actions">          <MoreHorizontalIcon />        </Button>      </DropdownMenuTrigger>      <DropdownMenuContent align="end" className="w-48">        <DropdownMenuItem>          <PencilIcon /> Edit          <DropdownMenuShortcut>⌘E</DropdownMenuShortcut>        </DropdownMenuItem>        <DropdownMenuItem>          <CopyIcon /> Duplicate          <DropdownMenuShortcut>⌘D</DropdownMenuShortcut>        </DropdownMenuItem>        <DropdownMenuSub>          <DropdownMenuSubTrigger>Share</DropdownMenuSubTrigger>          <DropdownMenuSubContent>            <DropdownMenuItem>Copy link</DropdownMenuItem>            <DropdownMenuItem>Email</DropdownMenuItem>            <DropdownMenuItem>Embed</DropdownMenuItem>          </DropdownMenuSubContent>        </DropdownMenuSub>        <DropdownMenuSeparator />        <DropdownMenuItem variant="destructive">          <Trash2Icon /> Delete          <DropdownMenuShortcut>⌫</DropdownMenuShortcut>        </DropdownMenuItem>      </DropdownMenuContent>    </DropdownMenu>  );}

Itens de checkbox

Alterne colunas ou filtros visíveis sem fechar o menu. Cada DropdownMenuCheckboxItem renderiza seu próprio indicador de check.

'use client';import { useState } from 'react';import { Button } from '@gremorie/rx-forms';import {  DropdownMenu,  DropdownMenuCheckboxItem,  DropdownMenuContent,  DropdownMenuLabel,  DropdownMenuSeparator,  DropdownMenuTrigger,} from '@gremorie/rx-overlays';export function DropdownMenuCheckboxesPreview() {  const [columns, setColumns] = useState({    name: true,    email: true,    role: false,  });  return (    <DropdownMenu>      <DropdownMenuTrigger asChild>        <Button variant="outline">Toggle columns</Button>      </DropdownMenuTrigger>      <DropdownMenuContent className="w-48">        <DropdownMenuLabel>Visible columns</DropdownMenuLabel>        <DropdownMenuSeparator />        <DropdownMenuCheckboxItem          checked={columns.name}          onCheckedChange={(checked) =>            setColumns((prev) => ({ ...prev, name: checked === true }))          }        >          Name        </DropdownMenuCheckboxItem>        <DropdownMenuCheckboxItem          checked={columns.email}          onCheckedChange={(checked) =>            setColumns((prev) => ({ ...prev, email: checked === true }))          }        >          Email        </DropdownMenuCheckboxItem>        <DropdownMenuCheckboxItem          checked={columns.role}          onCheckedChange={(checked) =>            setColumns((prev) => ({ ...prev, role: checked === true }))          }        >          Role        </DropdownMenuCheckboxItem>      </DropdownMenuContent>    </DropdownMenu>  );}

Itens de radio

Escolha um único valor de um DropdownMenuRadioGroup. O item selecionado renderiza um bullet auto-posicionado.

'use client';import { useState } from 'react';import { Button } from '@gremorie/rx-forms';import {  DropdownMenu,  DropdownMenuContent,  DropdownMenuLabel,  DropdownMenuRadioGroup,  DropdownMenuRadioItem,  DropdownMenuSeparator,  DropdownMenuTrigger,} from '@gremorie/rx-overlays';export function DropdownMenuRadioPreview() {  const [position, setPosition] = useState('bottom');  return (    <DropdownMenu>      <DropdownMenuTrigger asChild>        <Button variant="outline">Panel position</Button>      </DropdownMenuTrigger>      <DropdownMenuContent className="w-48">        <DropdownMenuLabel>Panel position</DropdownMenuLabel>        <DropdownMenuSeparator />        <DropdownMenuRadioGroup value={position} onValueChange={setPosition}>          <DropdownMenuRadioItem value="top">Top</DropdownMenuRadioItem>          <DropdownMenuRadioItem value="bottom">Bottom</DropdownMenuRadioItem>          <DropdownMenuRadioItem value="right">Right</DropdownMenuRadioItem>        </DropdownMenuRadioGroup>      </DropdownMenuContent>    </DropdownMenu>  );}

Itens com shortcuts e ação destrutiva

O menu canônico de ações de linha. Note os shortcuts alinhados à direita e a variante destructive para delete.

<DropdownMenu>
  <DropdownMenuTrigger asChild>
    <Button variant="ghost" size="icon" aria-label="Row actions">
      <MoreHorizontalIcon />
    </Button>
  </DropdownMenuTrigger>
  <DropdownMenuContent align="end">
    <DropdownMenuItem>
      <PencilIcon /> Edit
      <DropdownMenuShortcut>⌘E</DropdownMenuShortcut>
    </DropdownMenuItem>
    <DropdownMenuItem>
      <CopyIcon /> Duplicate
      <DropdownMenuShortcut>⌘D</DropdownMenuShortcut>
    </DropdownMenuItem>
    <DropdownMenuSeparator />
    <DropdownMenuItem variant="destructive">
      <Trash2Icon /> Delete
      <DropdownMenuShortcut>⌫</DropdownMenuShortcut>
    </DropdownMenuItem>
  </DropdownMenuContent>
</DropdownMenu>

Itens de checkbox

Alterne colunas ou filtros visíveis sem fechar o menu.

<DropdownMenuContent>
  <DropdownMenuLabel>Toggle columns</DropdownMenuLabel>
  <DropdownMenuSeparator />
  <DropdownMenuCheckboxItem
    checked={cols.name}
    onCheckedChange={toggle('name')}
  >
    Name
  </DropdownMenuCheckboxItem>
  <DropdownMenuCheckboxItem
    checked={cols.email}
    onCheckedChange={toggle('email')}
  >
    Email
  </DropdownMenuCheckboxItem>
</DropdownMenuContent>

Aninhe ações secundárias dentro de um sub-trigger.

<DropdownMenuContent>
  <DropdownMenuItem>Open</DropdownMenuItem>
  <DropdownMenuSub>
    <DropdownMenuSubTrigger>Share</DropdownMenuSubTrigger>
    <DropdownMenuSubContent>
      <DropdownMenuItem>Copy link</DropdownMenuItem>
      <DropdownMenuItem>Email</DropdownMenuItem>
      <DropdownMenuItem>Embed</DropdownMenuItem>
    </DropdownMenuSubContent>
  </DropdownMenuSub>
</DropdownMenuContent>

Acessibilidade

  • Role: role="menu" no content, role="menuitem" nos itens, role="menuitemcheckbox" e role="menuitemradio" nas variantes com estado.
  • Teclado: as setas navegam; Enter e Space ativam; o type-ahead salta para itens que começam com a letra digitada; Esc fecha; Tab fecha e continua o foco na página.
  • Submenus: abre, fecha.
  • Gestão de foco: o foco entra no menu na abertura e retorna ao trigger ao fechar.
  • aria-expanded é definido no trigger automaticamente; aria-controls liga ao id do content.
  • Variante destructive: apenas dica visual; emparelhe com confirmação (AlertDialog) se a ação for irreversível.
  • Reduced motion: as animações de abrir/fechar respeitam prefers-reduced-motion.

Relacionados

  • Context Menu - mesmo compound, acionado por clique direito em uma região.
  • Select - picker liderado por valores (países, status), não por ações.
  • Popover - overlay ancorado genérico quando os itens não seguem a semântica de menu.
  • Command - lista de comandos buscável para usuários avançados.

On this page