VsDropdownCustom
Grupo de 3 componentes que reimplementam e estendem o vs-dropdown do Vuesax com posicionamento dinâmico inteligente (detecta espaço disponível acima/abaixo e ajusta a posição), suporte a vsCustomContent (conteúdo livre no menu sem lista ul), trigger por click ou hover, suporte a contextmenu, alinhamento esquerda/direita, e fix de comportamento em iPhone/iOS. É o dropdown mais usado no admin (84 arquivos).
Trigger por Click (com vs-dropdown-item)
Padrão com vs-trigger-click — abre e fecha por click, não hover. Usa vs-dropdown-item para listar opções. Cada item fecha o dropdown automaticamente ao ser clicado. Usado no seletor de cor de tag de cliente.
<vs-dropdown vs-trigger-click class="cursor-pointer">
<div class="d-flex">
<vs-icon
v-for="(color, index) in takeTwoColors"
:key="index"
:color="color"
icon="label"
/>
</div>
<vs-dropdown-menu>
<vs-dropdown-item v-for="(group, index) in groups" :key="index">
<vs-icon icon="label" :color="group.color_tag" />
<div class="group-name ml-4">{{ group.name }}</div>
</vs-dropdown-item>
</vs-dropdown-menu>
</vs-dropdown>
Conteúdo Customizado (avatar trigger)
vs-custom-content + vs-trigger-click — o menu contém HTML livre (ul/li próprio) em vez de vs-dropdown-item. Padrão dominante no admin para dropdowns complexos (user menu, notificações). O menu é inserido no document.body para evitar overflow:hidden do pai.
<vs-dropdown
vs-custom-content
vs-trigger-click
class="user-dropdown-component cursor-pointer"
>
<div class="con-img">
<img
:src="activeUserInfo.image"
alt="user-img"
width="40"
height="40"
class="rounded-full shadow-md cursor-pointer block"
/>
</div>
<vs-dropdown-menu class="vx-navbar-dropdown">
<ul style="min-width: 9rem">
<li
class="flex py-2 px-4 cursor-pointer hover:bg-primary hover:text-white"
@click="$router.push('/user-settings').catch(() => {})"
>
<feather-icon icon="UserIcon" svgClasses="w-4 h-4" />
<span class="ml-2">Configurações</span>
</li>
<vs-divider class="m-1" />
<li
class="flex py-2 px-4 cursor-pointer hover:bg-primary hover:text-white"
@click="logout"
>
<feather-icon icon="LogOutIcon" svgClasses="w-4 h-4" />
<span class="ml-2">Logout</span>
</li>
</ul>
</vs-dropdown-menu>
</vs-dropdown>
Conteúdo Rico com Scroll (Notificações)
vs-custom-content com VuePerfectScrollbar dentro do menu — padrão do dropdown de notificações. O menu pode ter header colorido, lista com scroll e rodapé fixo. O trigger é um feather-icon com badge de contagem.
<vs-dropdown
vs-custom-content
vs-trigger-click
class="cursor-pointer"
>
<feather-icon
icon="BellIcon"
class="cursor-pointer"
:badge="unreadNotificationsBadge"
/>
<vs-dropdown-menu class="notification-dropdown dropdown-custom vx-navbar-dropdown">
<div class="notification-top text-center p-5 bg-primary text-white">
<h3 class="text-white">Notificações</h3>
</div>
<VuePerfectScrollbar
class="scroll-area--nofications-dropdown p-0"
:settings="settings"
>
<ul class="bordered-items" v-if="unreadNotifications.length > 0">
<!-- itens de notificação -->
</ul>
</VuePerfectScrollbar>
</vs-dropdown-menu>
</vs-dropdown>
Trigger por Hover (padrão)
Modo default — sem vs-trigger-click. Abre ao passar o mouse no trigger e fecha ao sair do menu. Nota: todos os 84 usos reais no admin adicionam vs-trigger-click — o hover puro nunca foi encontrado no codebase real.
Todos os 84 usos adicionam
vs-trigger-click. Use sempre vs-trigger-click para comportamento consistente.
<!-- Exemplo sintético — todos os usos reais usam vs-trigger-click -->
<vs-dropdown class="cursor-pointer">
<span>Opções</span>
<vs-dropdown-menu>
<vs-dropdown-item>Ação 1</vs-dropdown-item>
<vs-dropdown-item>Ação 2</vs-dropdown-item>
</vs-dropdown-menu>
</vs-dropdown>
Com Divider e Item Desabilitado
VsDropdownItem com :divider="true" adiciona linha separadora entre grupos. :disabled="true" impede o clique e não fecha o menu. Útil para separar ações destrutivas de operações normais.
<!-- Exemplo sintético — VsDropdownItem.divider/.disabled sem uso real encontrado -->
<vs-dropdown vs-trigger-click class="cursor-pointer">
<span>Ações</span>
<vs-dropdown-menu>
<vs-dropdown-item>Visualizar</vs-dropdown-item>
<vs-dropdown-item>Editar</vs-dropdown-item>
<vs-dropdown-item :divider="true" />
<vs-dropdown-item :disabled="true">Excluir (sem permissão)</vs-dropdown-item>
</vs-dropdown-menu>
</vs-dropdown>
Posicionamento Dinâmico
O VsDropdown detecta automaticamente o espaço disponível e abre o menu para cima quando não há espaço abaixo. O vsDropRight abre o menu para a direita do trigger; vsAlignLeft alinha pela borda esquerda.
<!-- Posicionamento calculado automaticamente pelo VsDropdown -->
<!-- Open above: automático quando não há espaço abaixo -->
<vs-dropdown vs-trigger-click class="cursor-pointer"> ... </vs-dropdown>
<!-- Drop right -->
<vs-dropdown vs-trigger-click vs-drop-right class="cursor-pointer"> ... </vs-dropdown>
<!-- Align left (default alinha pela borda direita) -->
<vs-dropdown vs-trigger-click vs-align-left class="cursor-pointer"> ... </vs-dropdown>
API
<!-- VsDropdown: vs-trigger-click (ou hover), vs-custom-content (menu livre), vs-drop-right, vs-align-left -->
<!-- VsDropdownItem: :to (router-link), :divider (separador), :disabled (não clicável) -->
<vs-dropdown
vs-trigger-click
vs-custom-content
color="primary"
class="cursor-pointer"
>
<!-- Trigger: qualquer elemento -->
<feather-icon icon="MoreVerticalIcon" />
<vs-dropdown-menu>
<!-- vsCustomContent=true: conteúdo livre -->
<ul>
<li @click="editItem">Editar</li>
<li @click="deleteItem">Excluir</li>
</ul>
<!-- sem vsCustomContent: usar vs-dropdown-item -->
<!-- <vs-dropdown-item :to="'/rota'">Link</vs-dropdown-item> -->
<!-- <vs-dropdown-item :disabled="true">Inativo</vs-dropdown-item> -->
<!-- <vs-dropdown-item :divider="true" /> -->
</vs-dropdown-menu>
</vs-dropdown>
Props — VsDropdown
| Nome (HTML) | Tipo | Default | Obrig. | Descrição |
|---|---|---|---|---|
vs-trigger-click |
Boolean | false | Não | Abre/fecha apenas por click. Sem este attr: hover. Fecha ao clicar fora (document click listener). |
vs-trigger-contextmenu |
Boolean | false | Não | Abre com botão direito. Previne menu nativo do browser. |
color |
String | "primary" | Não | Cor do hover nos VsDropdownItem filhos. Propagada via $children traversal. |
vs-custom-content |
Boolean | false | Não | Menu renderiza <div class="vs-dropdown--custom"> em vez de <ul>. Permite qualquer conteúdo. |
vs-drop-right |
Boolean | false | Não | Menu abre para a direita do trigger. Calcula leftx adicionando a largura do menu. |
vs-align-left |
Boolean | false | Não | Alinha o menu pela borda esquerda do trigger. Ignorado quando vsDropRight=true ou quando o menu ultrapassa a borda esquerda da viewport. |
Props — VsDropdownItem
| Nome | Tipo | Default | Obrig. | Descrição |
|---|---|---|---|---|
to |
Any | null | Não | Rota para router-link. Quando definido, renderiza <router-link :to="to">. Sem este prop: renderiza <a>. |
disabled |
Boolean | false | Não | Desabilita o item — classe .disabled e impede o fechamento do menu ao clicar. |
divider |
Boolean | false | Não | Linha separadora entre grupos — classe .divider no <li>. |
Slots
| Componente | Slot | Descrição |
|---|---|---|
| VsDropdown | default |
Conteúdo do botão trigger — texto, ícone, avatar, qualquer elemento. Wrapper é um <button type="button">. |
| VsDropdownMenu | default |
Conteúdo do menu. Sem vsCustomContent: deve conter VsDropdownItem. Com: conteúdo livre. |
| VsDropdownItem | default |
Conteúdo do item — texto, ícone + texto. Renderizado dentro do router-link ou a. |
Eventos — VsDropdown
| Evento | Payload | Descrição |
|---|---|---|
@click |
— | Emitido quando o trigger é clicado diretamente. Útil para detectar click no botão. |
@focus |
— | Emitido quando o dropdown é aberto (vsDropdownVisible = true). |
@blur |
— | Emitido quando o dropdown é fechado (vsDropdownVisible = false). |
Arquitetura dos Componentes
| Componente | Arquivo | Responsabilidade |
|---|---|---|
VsDropdown |
dropdown.vue | Botão trigger. Gerencia abertura/fechamento e calcula posição do menu. |
VsDropdownMenu |
dropdown-menu.vue | Menu flutuante. Inserido no document.body via insertBody() no mounted — evita overflow:hidden do pai. |
VsDropdownItem |
dropdown-item.vue | Item da lista. Fecha o dropdown ao clicar navegando via $parent recursivo até encontrar .parent-dropdown. |
Cuidados Importantes
$children traversal, não via props. VsDropdownMenu DEVE ser filho direto de VsDropdown. Inserir outros filhos entre eles quebra a comunicação.
<body> no mounted via insertBody(). Isso significa que ele não está no DOM do componente pai — estilos com escopo (scoped) não atingem o menu.
vs-trigger-click. O modo hover puro (default do componente) nunca é usado no admin. Use sempre vs-trigger-click.
vs-custom-content + HTML/ul/li próprio na maioria dos casos. O vs-dropdown-item aparece em poucos casos (tag color picker). Para dropdowns com layout customizado, prefira vs-custom-content.