Back to skills
SKILL.md
N Drawer
ASecurityDrawer component for slide-out panels and side navigation. Invoke when user needs to create slide-out panels, sidebars, or multi-level navigation drawers in Naive UI.
- 8 stars
- 0 votes
- 0 copies
- 5 views
- Added September 11, 2026
Works with
Security analysis
100/100npx -y skills add jiaiyan/naive-ui-skills --skill n-drawer --agent claude-codeAre you the author of N Drawer?
Add the live security badge to your README. It updates with every re-scan.
[](https://www.skillsdirectory.com/skills/jiaiyan-n-drawer)---
name: "n-drawer"
description: "Drawer component for slide-out panels and side navigation. Invoke when user needs to create slide-out panels, sidebars, or multi-level navigation drawers in Naive UI."
metadata:
author: jiaiyan
version: "1.0.0"
---
# Naive UI Drawer Component
Drawer component for slide-out panels, sidebars, and navigation from screen edges.
## When to Use
Use this component when:
- **Side navigation**: Display navigation menus or filters
- **Detail panels**: Show detailed information without leaving the page
- **Forms**: Collect user input in a slide-out panel
- **Multi-level content**: Nested drawer interactions
## When to Invoke
Invoke this skill when:
- User needs to create slide-out panels from any screen edge
- User wants to implement multi-level drawers
- User needs resizable drawer functionality
- User wants to customize drawer placement and size
- User asks about drawer content scrolling
## Features
- **Multiple Placements**: top, right, bottom, left
- **Resizable**: Drag to resize drawer width/height
- **Multiple Drawers**: Support for nested drawers
- **Customizable Size**: Control width and height
- **Scroll Support**: Native or custom scrollbar
- **Custom Display Area**: Render in specific container
- **Header and Footer**: Built-in header/footer slots
## API Reference
### Drawer Props
| Name | Type | Default | Description |
|------|------|---------|-------------|
| auto-focus | `boolean` | `true` | Whether to focus the first focusable element inside drawer. |
| block-scroll | `boolean` | `true` | Whether to disabled body scrolling when it's active. |
| close-on-esc | `boolean` | `true` | Whether to close drawer on Esc is pressed. |
| content-class | `string` | `undefined` | Class of drawer's scrollable content node. |
| content-style | `string \| Object` | `undefined` | Style of drawer's scrollable content node. |
| default-width | `number \| string` | `251` | Default width of the drawer, works when placement is `left` and `right`. |
| default-height | `number \| string` | `251` | Default height of the drawer, works when placement is `top` and `bottom`. |
| display-directive | `'if' \| 'show'` | `'if'` | The display directive to use. |
| height | `number \| string` | `undefined` | Works when placement is `top` and `bottom`. |
| native-scrollbar | `boolean` | `true` | Whether to use native scrollbar on drawer. |
| mask-closable | `boolean` | `true` | Whether to emit hide event when click mask. |
| max-width | `number` | `undefined` | Max width of resizable drawer. |
| max-height | `number` | `undefined` | Max height of resizable drawer. |
| min-width | `number` | `undefined` | Min width of resizable drawer. |
| min-height | `number` | `undefined` | Min height of resizable drawer. |
| placement | `'top' \| 'right' \| 'bottom' \| 'left'` | `'right'` | Drawer placement. |
| resizable | `boolean` | `false` | Whether to resize the width / height of drawer. |
| scrollbar-props | `ScrollbarProps` | `undefined` | Scrollbar props for custom scrollbar. |
| show | `boolean` | `false` | Whether to show drawer. |
| show-mask | `boolean \| 'transparent'` | `true` | Whether to show mask. |
| to | `string \| HTMLElement` | `'body'` | Container node of the drawer. |
| trap-focus | `boolean` | `true` | Whether to trap focus inside drawer. |
| width | `number \| string` | `undefined` | Works when placement is `left` and `right`. |
| z-index | `number` | `undefined` | Z index of the drawer. |
| on-after-enter | `() => void` | `undefined` | Callback after drawer is opened. |
| on-after-leave | `() => void` | `undefined` | Callback after drawer is closed. |
| on-mask-click | `(e: MouseEvent) => void` | `undefined` | Callback triggered on mask clicked. |
| on-update:show | `(show: boolean) => void` | `undefined` | Callback triggered on drawer display status change. |
### DrawerContent Props
| Name | Type | Default | Description |
|------|------|---------|-------------|
| body-class | `string` | `undefined` | Drawer content's body class. |
| body-style | `string \| Object` | `undefined` | Drawer content's body style. |
| closable | `boolean` | `false` | Whether the drawer content is closable. |
| footer-class | `string` | `undefined` | Drawer content's footer class. |
| footer-style | `string \| Object` | `undefined` | Drawer content's footer style. |
| header-class | `string` | `undefined` | Drawer content's header class. |
| header-style | `string \| Object` | `undefined` | Drawer content's header style. |
| native-scrollbar | `boolean` | `true` | Whether to use native scrollbar on body part. |
| title | `string` | `undefined` | Drawer content title. |
| scrollbar-props | `ScrollbarProps` | `undefined` | Scrollbar props. |
### Drawer Slots
| Name | Parameters | Description |
|------|------------|-------------|
| default | `()` | The content of the drawer. |
### DrawerContent Slots
| Name | Parameters | Description |
|------|------------|-------------|
| default | `()` | The content of the drawer content. |
| footer | `()` | The footer of the drawer content. |
| header | `()` | The header of the drawer content. |
## Basic Usage
### Basic Drawer
```vue
<template>
<n-button-group>
<n-button @click="activate('top')">Top</n-button>
<n-button @click="activate('right')">Right</n-button>
<n-button @click="activate('bottom')">Bottom</n-button>
<n-button @click="activate('left')">Left</n-button>
</n-button-group>
<n-drawer v-model:show="active" :width="502" :placement="placement">
<n-drawer-content title="Drawer Title">
Drawer content goes here
</n-drawer-content>
</n-drawer>
</template>
<script setup>
import { ref } from 'vue'
const active = ref(false)
const placement = ref('right')
const activate = (place) => {
placement.value = place
active.value = true
}
</script>
```
### Multiple Drawers
```vue
<template>
<n-button @click="showOuter = true">Open Outer Drawer</n-button>
<n-drawer v-model:show="showOuter" :width="502">
<n-drawer-content title="Outer Drawer">
<p>Outer drawer content</p>
<template #footer>
<n-button @click="showInner = true">Open Inner Drawer</n-button>
</template>
</n-drawer-content>
</n-drawer>
<n-drawer v-model:show="showInner" :width="300">
<n-drawer-content title="Inner Drawer">
<p>Inner drawer content</p>
</n-drawer-content>
</n-drawer>
</template>
<script setup>
import { ref } from 'vue'
const showOuter = ref(false)
const showInner = ref(false)
</script>
```
### Closable Drawer
```vue
<template>
<n-button @click="show = true">Open</n-button>
<n-drawer v-model:show="show" :width="502">
<n-drawer-content title="Closable Drawer" closable>
This drawer has a close button in the header
</n-drawer-content>
</n-drawer>
</template>
<script setup>
import { ref } from 'vue'
const show = ref(false)
</script>
```
### Custom Header and Footer
```vue
<template>
<n-button @click="show = true">Open</n-button>
<n-drawer v-model:show="show" :width="502">
<n-drawer-content>
<template #header>
<n-space align="center">
<n-icon><SettingsIcon /></n-icon>
<span>Custom Header</span>
</n-space>
</template>
Drawer content
<template #footer>
<n-space justify="end">
<n-button @click="show = false">Cancel</n-button>
<n-button type="primary" @click="handleSave">Save</n-button>
</n-space>
</template>
</n-drawer-content>
</n-drawer>
</template>
<script setup>
import { ref } from 'vue'
const show = ref(false)
const handleSave = () => {
console.log('Saved')
show.value = false
}
</script>
```
### Resizable Drawer
```vue
<template>
<n-button @click="show = true">Open Resizable</n-button>
<n-drawer
v-model:show="show"
:default-width="502"
placement="right"
resizable
:min-width="200"
:max-width="800"
>
<n-drawer-content title="Resizable Drawer">
Drag the edge to resize this drawer
</n-drawer-content>
</n-drawer>
</template>
<script setup>
import { ref } from 'vue'
const show = ref(false)
</script>
```
### Custom Display Area
```vue
<template>
<n-button @click="show = true">Open in Target</n-button>
<div
id="drawer-target"
style="position: relative; width: 100%; height: 300px; border: 1px solid #ccc;"
>
Target Area
</div>
<n-drawer
v-model:show="show"
:width="200"
placement="right"
:trap-focus="false"
:block-scroll="false"
to="#drawer-target"
>
<n-drawer-content title="Local Drawer">
Drawer inside target area
</n-drawer-content>
</n-drawer>
</template>
<script setup>
import { ref } from 'vue'
const show = ref(false)
</script>
```
### Scrollable Content
```vue
<template>
<n-button @click="show = true">Open Scrollable</n-button>
<n-drawer v-model:show="show" :width="480">
<n-drawer-content title="Scrollable Content" :native-scrollbar="false">
<p v-for="i in 50" :key="i">
Paragraph {{ i }}: Lorem ipsum dolor sit amet...
</p>
</n-drawer-content>
</n-drawer>
</template>
<script setup>
import { ref } from 'vue'
const show = ref(false)
</script>
```
## Common Patterns
### Navigation Drawer
```vue
<template>
<n-button @click="show = true">
<template #icon>
<n-icon><MenuIcon /></n-icon>
</template>
Menu
</n-button>
<n-drawer v-model:show="show" :width="240" placement="left">
<n-drawer-content title="Navigation">
<n-menu :options="menuOptions" @update:value="handleMenuSelect" />
</n-drawer-content>
</n-drawer>
</template>
<script setup>
import { ref, h } from 'vue'
import { NIcon } from 'naive-ui'
const show = ref(false)
const menuOptions = [
{ label: 'Home', key: 'home' },
{ label: 'About', key: 'about' },
{ label: 'Settings', key: 'settings' }
]
const handleMenuSelect = (key) => {
console.log('Selected:', key)
show.value = false
}
</script>
```
### Form in Drawer
```vue
<template>
<n-button @click="show = true">Edit Profile</n-button>
<n-drawer v-model:show="show" :width="400">
<n-drawer-content title="Edit Profile">
<n-form :model="form">
<n-form-item label="Name">
<n-input v-model:value="form.name" />
</n-form-item>
<n-form-item label="Email">
<n-input v-model:value="form.email" />
</n-form-item>
</n-form>
<template #footer>
<n-space justify="end">
<n-button @click="show = false">Cancel</n-button>
<n-button type="primary" @click="handleSave">Save</n-button>
</n-space>
</template>
</n-drawer-content>
</n-drawer>
</template>
<script setup>
import { ref, reactive } from 'vue'
const show = ref(false)
const form = reactive({
name: '',
email: ''
})
const handleSave = () => {
console.log('Saved:', form)
show.value = false
}
</script>
```
## Best Practices
1. **Use appropriate width/height**: Set reasonable sizes for different placements
```vue
<n-drawer :width="400" placement="right">
```
2. **Use default-width with resizable**: Provide initial size for resizable drawers
```vue
<n-drawer :default-width="502" resizable>
```
3. **Handle nested drawers**: Multiple drawers can stack naturally
4. **Use native-scrollbar with n-drawer-content**: Keep `native-scrollbar` true when using `n-drawer-content`
```vue
<n-drawer :native-scrollbar="true">
<n-drawer-content>...</n-drawer-content>
</n-drawer>
```
5. **Trap focus appropriately**: Disable `trap-focus` when drawer is in a custom container
```vue
<n-drawer to="#target" :trap-focus="false">
```
6. **Provide close options**: Either use `closable` prop or add close button in footer
Attribution
Comments
Loading comments…
Newsletter
Get the weekly list of safe new skills, and the ones we pulled.