Menu
Ações da linha
Fechado
Quais colunas mostrar
Ordenar por
Com submenu
import { Menu } from '@rivocode/ui'Quando usar
Menu de ações, típico dos três pontinhos de uma linha de tabela.
Compõe com MenuTrigger, MenuContent, MenuItem, MenuGroup e
MenuSeparator. O título de grupo e a propriedade label do MenuGroup, não
uma peça separada.
O menu também escolhe, e não só age: MenuCheckboxItem liga e desliga uma opção
sem fechar o painel (o "quais colunas mostrar" de uma listagem), e
MenuRadioGroup com MenuRadioItem faz a escolha única, o "ordenar por". Os
dois trazem o aria-checked de item de menu e a navegação por seta e por
primeira letra, que um Popover com Checkbox dentro não tem.
Quando um ramo merece painel próprio, MenuSubmenu com MenuSubmenuTrigger
abre ao lado. E o item que navega é MenuLinkItem, que sai como <a> de
verdade.
tone="danger" no item que apaga. Renderiza em portal, então exige o
RivoProvider.
No React Native
Traduz: o @rivocode/ui-native exporta Menu - folha de baixo com actions, nunca popup ancorado; children abre no toque longo. A API não é a mesma do web (no nativo tudo é controlado), e a tabela de paridade diz o que muda peça a peça.
API
| Prop | Tipo |
|---|---|
actionsRef0.4.0A ref to imperative actions. | RefObject<MenuRootActions | null> |
closeParentOnEsc0.4.0When in a submenu, determines whether pressing the Escape key closes the entire menu, or only the current child menu. | boolean |
defaultOpen0.4.0Whether the menu is initially open. | boolean |
defaultTriggerId0.4.0ID of the trigger that the menu is associated with. | string | null |
disabled0.4.0Whether the component should ignore user interaction. | boolean |
handle0.4.0A handle to associate the menu with a trigger. | MenuHandle<Payload> |
highlightItemOnHover0.4.0Whether moving the pointer over items should highlight them. | boolean |
loopFocus0.4.0Whether to loop keyboard focus back to the first item when the end of the list is reached while using the arrow keys. | boolean |
modal0.4.0Determines if the menu enters a modal state when open. | boolean |
onOpenChange0.4.0Event handler called when the menu is opened or closed. | ((open: boolean, eventDetails: MenuRootChangeEventDetails) => void) |
onOpenChangeComplete0.4.0Event handler called after any animations complete when the menu is opened or closed. | ((open: boolean) => void) |
open0.4.0Whether the menu is currently open. | boolean |
orientation0.4.0The visual orientation of the menu. | MenuRootOrientation |
triggerId0.4.0ID of the trigger that the menu is associated with. | string | null |
Partes
Menu se monta com estas peças. Todas vivem nesta página, porque separar cada uma num endereço obrigaria a abrir seis abas para montar uma tela.
MenuCheckboxItem
/menu-checkbox-item.mdUm item do menu que liga e desliga uma opção, sem fechar o menu.
É o menu de "Colunas" de uma listagem: quais colunas da tabela de notas
aparecem. Cada item guarda o próprio estado com defaultChecked, ou responde a
checked e onCheckedChange quando quem manda é a tela.
Marcar não fecha o menu (closeOnClick nasce false, como na Base UI),
porque quem escolhe colunas escolhe várias de uma vez.
<MenuContent>
<MenuGroup label="Mostrar na listagem">
<MenuCheckboxItem defaultChecked disabled>Número</MenuCheckboxItem>
<MenuCheckboxItem defaultChecked>Cliente</MenuCheckboxItem>
<MenuCheckboxItem>Valor</MenuCheckboxItem>
</MenuGroup>
</MenuContent>
Partes
classNames alcança o indicator, que é a coluna da marca. Ela existe mesmo no
item desmarcado de propósito: o indicador da Base UI só monta quando o item está
ligado, e sem uma coluna fixa o texto de todas as linhas andava para o lado a
cada clique. A largura é a mesma do SelectItem e do ComboboxItem, para as
três listas alinharem o texto na mesma coluna.
Quando não usar
Para uma escolha entre alternativas que se excluem (ordenar por data ou por
valor), use MenuRadioItem dentro de um MenuRadioGroup: o ponto diz que
escolher esta desescolhe a de cima, o que a marca de certo não diz.
E não troque por um Checkbox solto dentro de um Popover, que era o caminho
que sobrava antes desta peça. Ele custa as duas coisas que só o menu dá: o
aria-checked de item de menu, que é como o leitor de tela anuncia a linha, e a
navegação por seta e por primeira letra que a lista de menu já traz. Um Popover
é um painel com conteúdo qualquer; ninguém anda nele com o teclado como se anda
num menu.
Quando as opções são muitas e pedem busca, o menu não é o lugar: a lista com
campo de digitar é Combobox com multiple.
| Prop | Tipo |
|---|---|
checkedWhether the checkbox item is currently ticked. | boolean |
classNamesClasse por parte: `indicator`, a coluna que guarda a marca. | Partial<Record<"indicator", string>> |
closeOnClickWhether to close the menu when the item is clicked. | boolean |
defaultCheckedWhether the checkbox item is initially ticked. | boolean |
disabledWhether the component should ignore user interaction. | boolean |
labelOverrides the text label to use when the item is matched during keyboard text navigation. | string |
nativeButtonWhether the component renders a native `<button>` element when replacing it via the `render` prop. | boolean |
onCheckedChangeEvent handler called when the checkbox item is ticked or unticked. | ((checked: boolean, eventDetails: MenuRootChangeEventDetails) => void) |
onClickThe click handler for the menu item. | ((event: BaseUIEvent<MouseEvent<HTMLDivElement, MouseEvent>>) => void) |
renderAllows you to replace the component's HTML element with a different tag, or compose it with another component. | ComponentRenderFn<HTMLProps, MenuCheckboxItemState>ReactElement<unknown, stringJSXElementConstructor<any>> |
tone | "danger""neutral"null |
Além destas, a peça aceita className, style, id e children, repassados ao elemento de baixo.
MenuContent
/menu-content.mdO painel flutuante do menu, com portal, posicionamento e a virada de lado quando não cabe.
Usa a mesma casca visual do SelectContent e do TooltipContent: o que
flutua nesta biblioteca se parece de propósito. E se posiciona igual: side,
align e sideOffset significam a mesma coisa nas cinco, e abrem a 6px do
gatilho quando ninguém pede outra folga.
<MenuContent side="top" align="end">
<MenuItem>Baixar PDF</MenuItem>
</MenuContent>
| Prop | Tipo |
|---|---|
alignAlinhamento no eixo do lado escolhido. | Align |
finalFocus0.4.0Determines the element to focus when the menu is closed. | booleanRefObject<HTMLElementnull>((closeType: InteractionType) => voidbooleanHTMLElementnull) |
render0.4.0Allows you to replace the component's HTML element with a different tag, or compose it with another component. | ComponentRenderFn<HTMLProps, MenuPopupState>ReactElement<unknown, stringJSXElementConstructor<any>> |
sideLado preferido do gatilho. | Side |
sideOffsetDistancia entre o gatilho e o painel, em pixels. | number | OffsetFunction |
Além destas, a peça aceita className, style, id e children, repassados ao elemento de baixo.
MenuGroup
/menu-group.mdUm grupo de itens com título.
O rótulo vem junto no label de propósito: a Base UI exige que ele viva dentro
de um grupo, e expor as duas peças separadas só criava uma forma de usar errado
que quebra na tela, não no teste de tipo.
| Prop | Tipo |
|---|---|
classNamesClasse por parte: `label`, o titulo do grupo. | Partial<Record<"label", string>> |
label0.4.0Titulo do grupo. | string |
render0.4.0Allows you to replace the component's HTML element with a different tag, or compose it with another component. | ComponentRenderFn<HTMLProps, MenuGroupState>ReactElement<unknown, stringJSXElementConstructor<any>> |
Além destas, a peça aceita className, style, id e children, repassados ao elemento de baixo.
MenuItem
/menu-item.mdUma ação do menu.
tone="danger" pinta o que destrói. Use só no que não tem volta, se tudo é
vermelho, nada é. Item desativado continua na lista, porque sumir com a opção
esconde que ela existe.
| Prop | Tipo |
|---|---|
closeOnClick0.4.0Whether to close the menu when the item is clicked. | boolean |
disabled0.4.0Whether the component should ignore user interaction. | boolean |
label0.4.0Overrides the text label to use when the item is matched during keyboard text navigation. | string |
nativeButton0.4.0Whether the component renders a native `<button>` element when replacing it via the `render` prop. | boolean |
onClick0.4.0The click handler for the menu item. | ((event: BaseUIEvent<MouseEvent<HTMLDivElement, MouseEvent>>) => void) |
render0.4.0Allows you to replace the component's HTML element with a different tag, or compose it with another component. | ComponentRenderFn<HTMLProps, MenuItemState>ReactElement<unknown, stringJSXElementConstructor<any>> |
tone0.4.0 | "danger""neutral"null |
Além destas, a peça aceita className, style, id e children, repassados ao elemento de baixo.
MenuLinkItem
/menu-link-item.mdO item do menu que navega, e por isso sai como <a> de verdade.
É o "Meu perfil" do menu do avatar. O que se ganha é o que só a âncora tem: o botão do meio abre em outra aba, o botão direito copia o endereço, e a barra do navegador mostra para onde o item leva antes do clique.
<MenuContent>
<MenuLinkItem href="/perfil">Meu perfil</MenuLinkItem>
<MenuLinkItem render={<Link to="/assinatura" />}>Assinatura</MenuLinkItem>
</MenuContent>
Com roteador de uma página só, passe o componente de link dele em render: o
elemento é seu, e a peça só empresta a pele e o comportamento de menu.
closeOnClick nasce true aqui, e na Base UI nasce false. O motivo é a
navegação pelo cliente: sem recarregar a página ninguém desmonta o menu, e ele
ficava aberto flutuando sobre a tela nova. Quem quiser o comportamento da Base UI
passa closeOnClick={false}.
Quando não usar
Para o que acontece na mesma tela (duplicar, exportar, cancelar), use
MenuItem. Âncora que não leva a lugar nenhum (href="#" com onClick) engana
as três affordances acima, e é pior do que um item comum.
Um menu inteiro de links é um menu de navegação, e não de ações: aí a peça é
NavigationMenu, ou a Sidebar quando os destinos são as seções do painel.
| Prop | Tipo |
|---|---|
closeOnClickWhether to close the menu when the item is clicked. | boolean |
labelOverrides the text label to use when the item is matched during keyboard text navigation. | string |
renderAllows you to replace the component's HTML element with a different tag, or compose it with another component. | ComponentRenderFn<DetailedHTMLProps<AnchorHTMLAttributes<HTMLAnchorElement>, HTMLAnchorElement>, MenuLinkItemState> | ReactElement<...> |
Além destas, a peça aceita className, style, id e children, repassados ao elemento de baixo.
MenuRadioGroup
/menu-radio-group.mdO grupo de escolha única dentro do menu, e quem guarda o valor escolhido.
É o "Ordenar por" de uma listagem: uma ordem de cada vez. O valor vive aqui, e
não em cada item: defaultValue para deixar com a peça, value mais
onValueChange para deixar com a tela.
O título vem no label, pelo mesmo motivo do MenuGroup: a Base UI liga o
aria-labelledby do grupo ao título que mora dentro dele, e um título escrito
por fora não nomeia grupo nenhum (falha que não quebra tipo, só o anúncio).
<MenuRadioGroup defaultValue="emissao" label="Ordenar por">
<MenuRadioItem value="emissao" closeOnClick>Data de emissão</MenuRadioItem>
<MenuRadioItem value="valor" closeOnClick>Valor</MenuRadioItem>
</MenuRadioGroup>
Partes
classNames alcança o label, o mesmo título que o MenuGroup escreve.
Quando não usar
Para opções que se acumulam (quais colunas mostrar, quais situações incluir no
filtro), use MenuCheckboxItem: lá cada linha é independente, aqui uma linha
apaga a anterior.
Se as opções cabem na tela e comparar entre elas importa, o menu esconde o que
deveria estar à vista: RadioGroup mostra todas de uma vez, e ToggleGroup
resolve as duas ou três que viram botão. O menu é para quando a escolha não
merece ocupar espaço permanente na barra.
| Prop | Tipo |
|---|---|
classNamesClasse por parte: `label`, o titulo do grupo. | Partial<Record<"label", string>> |
defaultValueThe uncontrolled value of the radio item that should be initially selected. | any |
disabledWhether the component should ignore user interaction. | boolean |
labelTitulo do grupo: "Ordenar por". | string |
onValueChangeFunction called when the selected value changes. | ((value: any, eventDetails: MenuRootChangeEventDetails) => void) |
renderAllows you to replace the component's HTML element with a different tag, or compose it with another component. | ComponentRenderFn<HTMLProps, MenuRadioGroupState>ReactElement<unknown, stringJSXElementConstructor<any>> |
valueThe controlled value of the radio item that should be currently selected. | any |
Além destas, a peça aceita className, style, id e children, repassados ao elemento de baixo.
MenuRadioItem
/menu-radio-item.mdUma opção de escolha única no menu: "por data de emissão", "por valor".
Sempre dentro de um MenuRadioGroup, que é quem guarda o valor. O value é
obrigatório: é ele que o grupo compara para saber qual linha está escolhida.
O ponto no lugar da marca de certo não é decoração: ele diz que escolher esta desescolhe a de cima.
Como na Base UI, escolher não fecha o menu. Quando a escolha encerra o
assunto, e ordenar costuma encerrar, passe closeOnClick.
Partes
classNames alcança o indicator, a coluna que guarda o ponto (a mesma
largura do MenuCheckboxItem, para os dois alinharem o texto quando aparecem no
mesmo painel).
Quando não usar
Para ligar e desligar cada opção por conta, use MenuCheckboxItem.
Para uma ação que acontece e acaba (baixar o PDF, cancelar a nota), use
MenuItem: aria-checked num item que não guarda estado nenhum diz ao leitor de
tela que há uma escolha marcada onde não há.
| Prop | Tipo |
|---|---|
valueobrigatóriaValue of the radio item. | any |
classNamesClasse por parte: `indicator`, a coluna que guarda o ponto. | Partial<Record<"indicator", string>> |
closeOnClickWhether to close the menu when the item is clicked. | boolean |
disabledWhether the component should ignore user interaction. | boolean |
labelOverrides the text label to use when the item is matched during keyboard text navigation. | string |
nativeButtonWhether the component renders a native `<button>` element when replacing it via the `render` prop. | boolean |
onClickThe click handler for the menu item. | ((event: BaseUIEvent<MouseEvent<HTMLDivElement, MouseEvent>>) => void) |
renderAllows you to replace the component's HTML element with a different tag, or compose it with another component. | ComponentRenderFn<HTMLProps, MenuRadioItemState>ReactElement<unknown, stringJSXElementConstructor<any>> |
tone | "danger""neutral"null |
Além destas, a peça aceita className, style, id e children, repassados ao elemento de baixo.
MenuSeparator
/menu-separator.mdA linha entre grupos de ação.
Separa o que muda a tela do que muda o dado, e o comum do destrutivo. Duas separações seguidas viram enfeite.
| Prop | Tipo |
|---|---|
orientation0.4.0The orientation of the separator. | Orientation |
render0.4.0Allows you to replace the component's HTML element with a different tag, or compose it with another component. | ComponentRenderFn<HTMLProps, SeparatorState>ReactElement<unknown, stringJSXElementConstructor<any>> |
Além destas, a peça aceita className, style, id e children, repassados ao elemento de baixo.
MenuSubmenu
/menu-submenu.mdUm ramo do menu, que abre ao lado.
Não pinta elemento nenhum: é só estado. Dentro dele vão o MenuSubmenuTrigger,
que é o item que abre o ramo, e um MenuContent, que é o mesmo painel do menu
de cima.
O lado não precisa ser pedido. A Base UI abre o ramo em inline-end quando o
pai é um menu, e vira para o outro lado sozinha quando não cabe. Passar side
aqui é para quem tem motivo, não obrigação.
<MenuContent>
<MenuItem>Duplicar</MenuItem>
<MenuSubmenu>
<MenuSubmenuTrigger>Exportar</MenuSubmenuTrigger>
<MenuContent>
<MenuItem>XML da NF-e</MenuItem>
<MenuItem>PDF do DANFE</MenuItem>
</MenuContent>
</MenuSubmenu>
</MenuContent>
O MenuSubmenuTrigger traz a seta que avisa que há mais adiante, e classNames
alcança ela pelo nome indicator. O item fica aceso enquanto o ramo está
aberto: sem isso o realce sai assim que o ponteiro entra no painel filho, e nada
mais liga um ao outro.
Quando não usar
Um nível resolve quase tudo. Dois já é uma árvore, e árvore com o mouse em cima
é como andar na diagonal sem perder a linha: quem escorrega fecha o ramo inteiro
e recomeça. Passando disso, Dialog ou uma tela própria custam menos a quem usa.
Para o menu que abre no botão direito sobre uma área, o gatilho é outro:
ContextMenu. E para a navegação principal do site, com painéis largos e links,
é NavigationMenu: o submenu daqui é uma lista de ações, e não um mapa de
seções.
| Prop | Tipo |
|---|---|
actionsRefA ref to imperative actions. | RefObject<MenuRootActions | null> |
closeParentOnEscWhen in a submenu, determines whether pressing the Escape key closes the entire menu, or only the current child menu. | boolean |
defaultOpenWhether the menu is initially open. | boolean |
disabledWhether the component should ignore user interaction. | boolean |
highlightItemOnHoverWhether moving the pointer over items should highlight them. | boolean |
loopFocusWhether to loop keyboard focus back to the first item when the end of the list is reached while using the arrow keys. | boolean |
onOpenChangeEvent handler called when the menu is opened or closed. | ((open: boolean, eventDetails: MenuRootChangeEventDetails) => void) |
onOpenChangeCompleteEvent handler called after any animations complete when the menu is opened or closed. | ((open: boolean) => void) |
openWhether the menu is currently open. | boolean |
orientationThe visual orientation of the menu. | MenuRootOrientation |
MenuTrigger
/menu-trigger.mdO que abre o menu.
Sem estilo próprio de propósito: quase sempre ele envolve um Button por
render, e um estilo aqui brigaria com o do botão.
| Prop | Tipo |
|---|---|
closeDelay0.4.0How long to wait before closing the menu that was opened on hover. | number |
delay0.4.0How long to wait before the menu may be opened on hover. | number |
disabled0.4.0Whether the component should ignore user interaction. | boolean |
handle0.4.0A handle to associate the trigger with a menu. | MenuHandle<unknown> |
nativeButton0.4.0Whether the component renders a native `<button>` element when replacing it via the `render` prop. | boolean |
openOnHover0.4.0Whether the menu should also open when the trigger is hovered. | boolean |
payload0.4.0A payload to pass to the menu when it is opened. | unknown |
render0.4.0Allows you to replace the component's HTML element with a different tag, or compose it with another component. | ComponentRenderFn<HTMLProps, MenuTriggerState>ReactElement<unknown, stringJSXElementConstructor<any>> |
Além destas, a peça aceita className, style, id e children, repassados ao elemento de baixo.