Pular para o conteúdo principal

ContextualMenu

O componente ContextualMenu é um menu overlay que aparece em resposta a uma ação do usuário, fornecendo uma lista de opções contextuais. Ideal para ações secundárias, filtros ou menus de navegação em dispositivos móveis.

Importação

import { ContextualMenu } from '@useblu/ocean-react';

Importação específica (recomendado para tree-shaking)

import { ContextualMenu } from '@useblu/ocean-react/ContextualMenu';

Importação de tipos TypeScript

import type {
ContextualMenuProps,
ContextualMenuItemProps,
} from '@useblu/ocean-react';

// Uso em componente customizado
const MyMenu: React.FC<ContextualMenuProps> = (props) => {
return <ContextualMenu {...props} />;
};

Playground Interativo

Explore o componente ContextualMenu no playground interativo do Storybook:

Documentação Completa

Para documentação técnica detalhada, exemplos de uso e API completa, consulte o Storybook do ContextualMenu.

No Storybook você encontrará:

  • Controles interativos para testar todas as props
  • API gerada automaticamente com tipagem completa
  • Exemplos visuais de todas as variantes e estados
  • Playground para experimentação rápida

Uso básico

function ContextualMenuExample() {
const [open, setOpen] = React.useState(false);
const [selectedValue, setSelectedValue] = React.useState('');

return (
<div style={{ position: 'relative', minHeight: '400px' }}>
<button onClick={() => setOpen(true)}>Abrir Menu</button>
<ContextualMenu
items={[
{ type: 'primary', label: 'Opção 1', value: 'option1' },
{ type: 'neutral', label: 'Opção 2', value: 'option2' },
{ type: 'critical', label: 'Excluir', value: 'delete' },
]}
open={open}
onOpenChange={setOpen}
onSelect={(value) => {
setSelectedValue(value);
alert(`Selecionado: ${value}`);
}}
selectedValue={selectedValue}
/>
</div>
);
}

Tipos de itens

O ContextualMenu oferece três tipos diferentes de itens para diferentes contextos:

Primary

Usado para ações principais e opções recomendadas.

function PrimaryExample() {
const [open, setOpen] = React.useState(false);

return (
<div style={{ position: 'relative', minHeight: '300px' }}>
<button onClick={() => setOpen(true)}>Abrir Menu Primary</button>
<ContextualMenu
items={[
{ type: 'primary', label: 'Criar novo', value: 'create' },
{ type: 'primary', label: 'Editar', value: 'edit' },
{ type: 'primary', label: 'Duplicar', value: 'duplicate' },
]}
open={open}
onOpenChange={setOpen}
/>
</div>
);
}

Neutral

Usado para ações padrão e opções informativas.

function NeutralExample() {
const [open, setOpen] = React.useState(false);

return (
<div style={{ position: 'relative', minHeight: '300px' }}>
<button onClick={() => setOpen(true)}>Abrir Menu Neutral</button>
<ContextualMenu
items={[
{ type: 'neutral', label: 'Visualizar', value: 'view' },
{ type: 'neutral', label: 'Compartilhar', value: 'share' },
{ type: 'neutral', label: 'Copiar link', value: 'copy' },
]}
open={open}
onOpenChange={setOpen}
/>
</div>
);
}

Critical

Usado para ações destrutivas e de remoção.

function CriticalExample() {
const [open, setOpen] = React.useState(false);

return (
<div style={{ position: 'relative', minHeight: '300px' }}>
<button onClick={() => setOpen(true)}>Abrir Menu Critical</button>
<ContextualMenu
items={[
{ type: 'neutral', label: 'Editar', value: 'edit' },
{ type: 'critical', label: 'Arquivar', value: 'archive' },
{ type: 'critical', label: 'Excluir', value: 'delete' },
]}
open={open}
onOpenChange={setOpen}
/>
</div>
);
}

Guia de uso dos tipos

  • primary: Para ações principais, recomendadas ou de criação
  • neutral: Para ações padrão, informativas ou de navegação
  • critical: Para ações destrutivas, arquivamento ou exclusão

Estados

Disabled

Desabilita a interação com um item específico do menu.

function DisabledExample() {
const [open, setOpen] = React.useState(false);

return (
<div style={{ position: 'relative', minHeight: '300px' }}>
<button onClick={() => setOpen(true)}>Abrir Menu</button>
<ContextualMenu
items={[
{ type: 'primary', label: 'Opção ativa', value: 'active' },
{
type: 'neutral',
label: 'Opção desabilitada',
value: 'disabled',
disabled: true,
},
{ type: 'neutral', label: 'Outra opção ativa', value: 'active2' },
]}
open={open}
onOpenChange={setOpen}
/>
</div>
);
}

Blocked

Indica que um item requer uma ação ou permissão adicional.

function BlockedExample() {
const [open, setOpen] = React.useState(false);

return (
<div style={{ position: 'relative', minHeight: '300px' }}>
<button onClick={() => setOpen(true)}>Abrir Menu</button>
<ContextualMenu
items={[
{ type: 'primary', label: 'Recurso disponível', value: 'available' },
{
type: 'primary',
label: 'Recurso premium',
value: 'premium',
blocked: true,
},
{
type: 'neutral',
label: 'Recurso bloqueado',
value: 'blocked',
blocked: true,
},
]}
open={open}
onOpenChange={setOpen}
/>
</div>
);
}

Selected

Indica o item atualmente selecionado no menu.

function SelectedExample() {
const [open, setOpen] = React.useState(false);
const [selectedValue, setSelectedValue] = React.useState('option2');

return (
<div style={{ position: 'relative', minHeight: '300px' }}>
<button onClick={() => setOpen(true)}>Abrir Menu</button>
<ContextualMenu
items={[
{ type: 'neutral', label: 'Opção 1', value: 'option1' },
{ type: 'neutral', label: 'Opção 2', value: 'option2' },
{ type: 'neutral', label: 'Opção 3', value: 'option3' },
]}
open={open}
onOpenChange={setOpen}
onSelect={setSelectedValue}
selectedValue={selectedValue}
/>
</div>
);
}

Recursos adicionais

Com ícones

Adicione ícones para melhorar a identificação visual das opções.

function IconExample() {
const [open, setOpen] = React.useState(false);
const Trash = () => (
<svg width="16" height="16" viewBox="0 0 16 16" fill="currentColor">
<path d="M2 4h12v10a2 2 0 01-2 2H4a2 2 0 01-2-2V4zm3-3h6v2H5V1z" />
</svg>
);

return (
<div style={{ position: 'relative', minHeight: '300px' }}>
<button onClick={() => setOpen(true)}>Abrir Menu com Ícones</button>
<ContextualMenu
items={[
{ type: 'neutral', label: 'Editar', value: 'edit' },
{
type: 'critical',
label: 'Excluir',
value: 'delete',
icon: <Trash />,
},
]}
open={open}
onOpenChange={setOpen}
/>
</div>
);
}

Com tags

Use tags para adicionar informações complementares aos itens.

function TagExample() {
const [open, setOpen] = React.useState(false);

return (
<div style={{ position: 'relative', minHeight: '300px' }}>
<button onClick={() => setOpen(true)}>Abrir Menu com Tags</button>
<ContextualMenu
items={[
{
type: 'primary',
label: 'Recurso novo',
value: 'new',
tag: { variant: 'highlight', type: 'important', children: 'Novo' },
},
{
type: 'neutral',
label: 'Recurso beta',
value: 'beta',
tag: { variant: 'highlight', type: 'neutral', children: 'Beta' },
},
]}
open={open}
onOpenChange={setOpen}
/>
</div>
);
}

API

ContextualMenuProps

PropTipoPadrãoObrigatórioDescrição
itemsContextualMenuItemProps[]-Array de itens do menu
openboolean-Define se o menu está aberto ou fechado (controlado)
onOpenChange(open: boolean) => void-Callback chamado quando o estado open muda
onSelect(value: string) => void--Callback chamado ao selecionar um item (opcional)
selectedValuestring--Valor do item atualmente selecionado (opcional)
classNamestring--Classes CSS adicionais (opcional)

ContextualMenuItemProps

PropTipoPadrãoDescrição
labelstring-Texto do item do menu
valuestring-Valor único identificador do item
type'primary' | 'neutral' | 'critical'-Tipo visual do item
iconReactNode-Ícone exibido à esquerda do texto
disabledbooleanfalseDesabilita o item
blockedbooleanfalseIndica que o item está bloqueado
tagTagProps-Tag exibida à direita do texto
idstring-ID HTML do elemento

Eventos

  • onOpenChange: Disparado quando o estado de abertura do menu muda (ao abrir/fechar)
  • onSelect: Disparado quando um item do menu é selecionado

Acessibilidade

  • ✅ Navegação por teclado completa
  • ✅ Estados de foco visíveis
  • ✅ Atributos ARIA apropriados
  • ✅ Suporte a screen readers
  • ✅ Estados disabled adequadamente sinalizados
  • ✅ Fechamento com tecla ESC
  • ✅ Fechamento ao clicar fora do menu (overlay)
TeclaFunção
TabMove o foco entre itens do menu
EnterSeleciona o item focado
SpaceSeleciona o item focado
EscFecha o menu

Melhores práticas

✅ Faça

  • Use tipos de item apropriados para o contexto (critical para ações destrutivas)
  • Agrupe itens relacionados visualmente (use tipos similares consecutivamente)
  • Forneça feedback visual ao selecionar um item (use selectedValue)
  • Use ícones para melhorar a identificação rápida de ações
  • Limite o número de itens para evitar scroll excessivo
  • Use estado blocked para indicar recursos premium ou restritos

❌ Não faça

  • Não use textos muito longos nos itens (mantenha conciso)
  • Não misture muitos tipos diferentes consecutivamente
  • Não use múltiplas ações críticas sem agrupamento claro
  • Não omita feedback ao selecionar itens
  • Não deixe o menu aberto após selecionar um item (o menu fecha automaticamente ao selecionar)
  • Não abuse de tags (use apenas quando adicionar valor informativo)

Variantes no Storybook

Veja todas as variantes do ContextualMenu:

Variantes Primary

Variantes Neutral

Variantes Critical