Dropdown component for displaying contextual menus and action lists. Invoke when user needs to implement dropdown menus, context menus, or cascading selections in Naive UI.
Scanned 9/11/2026
Install to Claude Code
npx -y skills add jiaiyan/naive-ui-skills --skill n-dropdown --agent claude-codeInstalls into .claude/skills of the current project.
Are you the author of N Dropdown?
Add the live security badge to your README — it updates automatically with every re-scan.
[](https://www.skillsdirectory.com/skills/jiaiyan-n-dropdown)More formats (shields.io, HTML) on the badges page.
---
name: "n-dropdown"
description: "Dropdown component for displaying contextual menus and action lists. Invoke when user needs to implement dropdown menus, context menus, or cascading selections in Naive UI."
metadata:
author: jiaiyan
version: "1.0.0"
---
# Naive UI Dropdown Component
Dropdown component for displaying contextual menus, action lists, and cascading selections.
## When to Use
Use this component when:
- **Context menus**: Right-click or action-triggered menus
- **Navigation menus**: Dropdown navigation items
- **Action lists**: Lists of actions for an item
- **User menus**: Profile and settings dropdowns
## When to Invoke
Invoke this skill when:
- User needs to implement a dropdown menu
- User wants cascading (nested) menus
- User needs context menu (right-click menu)
- User wants to customize option rendering
- User asks about different trigger modes (hover, click, manual)
- User needs to add icons or tooltips to options
## Features
- **Multiple Triggers**: Hover, click, or manual control
- **Cascading Menus**: Support for nested submenus
- **Custom Rendering**: Full control over option rendering
- **Context Menu**: Manual positioning for right-click menus
- **Icons Support**: Add icons to menu options
- **Grouping**: Group related options together
- **Keyboard Navigation**: Full keyboard support
- **Placement Control**: Configurable popup placement
## API Reference
### Dropdown Props
| Name | Type | Default | Description |
|------|------|---------|-------------|
| animated | `boolean` | `true` | Use animation when showing options. |
| inverted | `boolean` | `false` | Use inverted style. |
| children-field | `string` | `'children'` | Field name of children. |
| keyboard | `boolean` | `true` | Whether keyboard operation is supported. |
| key-field | `string` | `'key'` | Field name of key. |
| label-field | `string` | `'label'` | Field name of label. |
| node-props | `(option) => HTMLAttributes` | `undefined` | Option HTML attributes generator. |
| menu-props | `(option, options) => HTMLAttributes` | `undefined` | Menu HTML attributes generator. |
| options | `Array<DropdownOption>` | `[]` | Dropdown options. |
| render-icon | `(option) => VNodeChild` | `undefined` | Render function for option icons. |
| render-label | `(option) => VNodeChild` | `undefined` | Render function for option labels. |
| render-option | `({ node, option }) => VNodeChild` | `undefined` | Render function for option itself. |
| size | `'small' \| 'medium' \| 'large' \| 'huge'` | `'medium'` | Dropdown size. |
| on-clickoutside | `(e: MouseEvent) => void` | `undefined` | Callback when click outside. |
| on-select | `(key, option) => void` | `undefined` | Callback when option is selected. |
### DropdownOption Type
| Property | Type | Description |
|----------|------|-------------|
| children? | `Array<DropdownOption>` | Child options (for cascading). |
| disabled? | `boolean` | Whether to disable the option. |
| icon? | `() => VNodeChild` | Custom render function for icon. |
| key? | `string \| number` | Option ID (should be unique). |
| label? | `string \| () => VNodeChild` | Displayed label value. |
| props? | `HTMLAttributes` | Customize option props. |
| show? | `boolean` | Whether to show the option. |
### DropdownDividerOption Type
| Property | Type | Description |
|----------|------|-------------|
| key? | `string \| number` | Divider ID. |
| show? | `boolean` | Whether to show. |
| type | `'divider'` | The type identifier. |
### DropdownGroupOption Type
| Property | Type | Description |
|----------|------|-------------|
| children? | `Array<DropdownOption>` | Children options. |
| icon? | `() => VNodeChild` | Custom icon render. |
| label? | `string` | Group label. |
| key? | `string \| number` | Group ID. |
| show? | `boolean` | Whether to show. |
| type | `'group'` | The type identifier. |
### DropdownRenderOption Type
| Property | Type | Description |
|----------|------|-------------|
| key? | `string \| number` | Render option ID. |
| render? | `() => VNodeChild` | Render function for content. |
| show? | `boolean` | Whether to show. |
| type | `'render'` | The type identifier. |
## Basic Usage
### Basic Dropdown
```vue
<template>
<n-dropdown trigger="hover" :options="options" @select="handleSelect">
<n-button>Hover Me</n-button>
</n-dropdown>
</template>
<script setup>
const options = [
{ label: 'Edit', key: 'edit' },
{ label: 'Delete', key: 'delete' },
{ label: 'Share', key: 'share' }
]
const handleSelect = (key) => {
console.log(`Selected: ${key}`)
}
</script>
```
### Click Trigger
```vue
<template>
<n-dropdown trigger="click" :options="options" @select="handleSelect">
<n-button>Click Me</n-button>
</n-dropdown>
</template>
```
### Dropdown with Icons
```vue
<template>
<n-dropdown :options="options">
<n-button>User Profile</n-button>
</n-dropdown>
</template>
<script setup>
import { h } from 'vue'
import { PersonOutline, SettingsOutline, LogOutOutline } from '@vicons/ionicons5'
const options = [
{
label: 'Profile',
key: 'profile',
icon: () => h(PersonOutline)
},
{
label: 'Settings',
key: 'settings',
icon: () => h(SettingsOutline)
},
{
type: 'divider',
key: 'd1'
},
{
label: 'Logout',
key: 'logout',
icon: () => h(LogOutOutline)
}
]
</script>
```
## Common Patterns
### Cascading Menu
```vue
<template>
<n-dropdown
:options="options"
placement="bottom-start"
trigger="click"
@select="handleSelect"
>
<n-button>Menu</n-button>
</n-dropdown>
</template>
<script setup>
const options = [
{
label: 'File',
key: 'file',
children: [
{ label: 'New', key: 'new' },
{ label: 'Open', key: 'open' },
{ type: 'divider', key: 'd1' },
{ label: 'Save', key: 'save' }
]
},
{
label: 'Edit',
key: 'edit',
children: [
{ label: 'Undo', key: 'undo' },
{ label: 'Redo', key: 'redo' }
]
}
]
</script>
```
### Context Menu (Right-Click)
```vue
<template>
<div
style="width: 200px; height: 200px; background: rgba(0, 128, 0, 0.5)"
@contextmenu="handleContextMenu"
>
Right Click Here
</div>
<n-dropdown
placement="bottom-start"
trigger="manual"
:x="x"
:y="y"
:options="options"
:show="showDropdown"
:on-clickoutside="onClickoutside"
@update:show="showDropdown = $event"
@select="handleSelect"
/>
</template>
<script setup>
import { ref } from 'vue'
const showDropdown = ref(false)
const x = ref(0)
const y = ref(0)
const options = [
{ label: 'Copy', key: 'copy' },
{ label: 'Paste', key: 'paste' },
{ label: 'Delete', key: 'delete' }
]
const handleContextMenu = (e) => {
e.preventDefault()
showDropdown.value = false
x.value = e.clientX
y.value = e.clientY
showDropdown.value = true
}
const onClickoutside = () => {
showDropdown.value = false
}
const handleSelect = () => {
showDropdown.value = false
}
</script>
```
### Grouped Options
```vue
<template>
<n-dropdown :options="options" trigger="click">
<n-button>Grouped Menu</n-button>
</n-dropdown>
</template>
<script setup>
const options = [
{
type: 'group',
label: 'Actions',
key: 'actions',
children: [
{ label: 'Edit', key: 'edit' },
{ label: 'Delete', key: 'delete' }
]
},
{
type: 'divider',
key: 'd1'
},
{
type: 'group',
label: 'Export',
key: 'export',
children: [
{ label: 'PDF', key: 'pdf' },
{ label: 'Excel', key: 'excel' }
]
}
]
</script>
```
### Custom Render
```vue
<template>
<n-dropdown
:options="options"
:render-label="renderLabel"
:render-icon="renderIcon"
trigger="click"
>
<n-button>Custom Render</n-button>
</n-dropdown>
</template>
<script setup>
import { h } from 'vue'
import { NText } from 'naive-ui'
const options = [
{ label: 'Edit', key: 'edit' },
{ label: 'Delete', key: 'delete', disabled: true }
]
const renderLabel = (option) => {
return h(NText, { type: option.disabled ? 'disabled' : 'default' }, {
default: () => option.label
})
}
const renderIcon = (option) => {
if (option.key === 'edit') {
return h('span', '✏️')
}
return null
}
</script>
```
### With Arrow
```vue
<template>
<n-dropdown
trigger="click"
:options="options"
:show-arrow="true"
@select="handleSelect"
>
<n-button>Dropdown with Arrow</n-button>
</n-dropdown>
</template>
```
### Placement Control
```vue
<template>
<n-space>
<n-dropdown placement="bottom-start" :options="options" trigger="click">
<n-button>Bottom Start</n-button>
</n-dropdown>
<n-dropdown placement="bottom-end" :options="options" trigger="click">
<n-button>Bottom End</n-button>
</n-dropdown>
<n-dropdown placement="top" :options="options" trigger="click">
<n-button>Top</n-button>
</n-dropdown>
</n-space>
</template>
```
### Different Sizes
```vue
<template>
<n-space>
<n-dropdown size="small" :options="options" trigger="click">
<n-button>Small</n-button>
</n-dropdown>
<n-dropdown size="medium" :options="options" trigger="click">
<n-button>Medium</n-button>
</n-dropdown>
<n-dropdown size="large" :options="options" trigger="click">
<n-button>Large</n-button>
</n-dropdown>
</n-space>
</template>
```
### Add Tooltip for Option
```vue
<template>
<n-dropdown
trigger="hover"
:options="options"
:render-option="renderOption"
@select="handleSelect"
>
<n-button>With Tooltips</n-button>
</n-dropdown>
</template>
<script setup>
import { h } from 'vue'
import { NTooltip } from 'naive-ui'
const options = [
{ label: 'Edit', key: 'edit' },
{ label: 'Delete', key: 'delete' }
]
const renderOption = ({ node, option }) => {
return h(NTooltip, null, {
trigger: () => node,
default: () => `Click to ${option.label}`
})
}
</script>
```
### Pure Render Content
```vue
<template>
<n-dropdown trigger="hover" :options="options">
<n-button>Custom Content</n-button>
</n-dropdown>
</template>
<script setup>
import { h } from 'vue'
import { NText } from 'naive-ui'
const options = [
{
type: 'render',
key: 'render',
render: () => h(NText, { type: 'primary' }, { default: () => 'Custom rendered content' })
}
]
</script>
```
## Best Practices
1. **Use appropriate trigger**: Choose hover or click based on use case
- Hover: Quick access menus
- Click: Action menus, forms
- Manual: Context menus
2. **Unique keys**: Ensure each option has a unique key
```javascript
{ label: 'Edit', key: 'edit' }
```
3. **Group related options**: Use dividers and groups
```javascript
[
{ label: 'Edit', key: 'edit' },
{ type: 'divider', key: 'd1' },
{ label: 'Delete', key: 'delete' }
]
```
4. **Disable unavailable options**: Use `disabled` for unavailable actions
```javascript
{ label: 'Delete', key: 'delete', disabled: true }
```
5. **Context menu pattern**: Always handle clickoutside for manual triggers
```vue
<n-dropdown
trigger="manual"
:on-clickoutside="() => show = false"
/>
```
6. **Keyboard accessibility**: Keep `keyboard` enabled for accessibility
```vue
<n-dropdown keyboard :options="options">
```
7. **Icons for clarity**: Add icons to improve visual recognition
```javascript
{ label: 'Delete', key: 'delete', icon: () => h(TrashIcon) }
```
Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.
No comments yet. Be the first to comment!