Drawer
A pixel-art sidebar panel that slides in from the edge of the screen.
| Name | Category | Description | Type | Default |
|---|---|---|---|---|
showOverlay | Style | Whether to show the overlay backdrop | boolean | true |
size | Size | Drawer width | string | '300px' |
v-model | State | Whether the drawer is open | boolean | false |
placement | Behavior | Drawer placement side | 'left' | 'right' | 'left' |
lockScroll | Behavior | Whether to lock body scroll when open | boolean | true |
closeOnClickOverlay | Behavior | Whether clicking the overlay closes the drawer | boolean | true |
closeOnEsc | Behavior | Whether pressing Escape closes the drawer | boolean | true |
title | Content | Drawer title | string | — |
update:modelValue | Event | Triggered when open state changes | (value: boolean) => void | — |
open | Event | Triggered when the drawer opens | () => void | — |
close | Event | Triggered when the drawer closes | () => void | — |
default | Slot | Main page content | — | |
sidebar | Slot | Drawer sidebar content | — | |
open | Expose | Open the drawer | () => void | — |
close | Expose | Close the drawer | () => void | — |
toggle | Expose | Toggle drawer open/close | () => void | — |
Basic Usage
Use v-model to control the drawer open/close state. Content goes in the sidebar slot.
<template>
<div>
<px-button @click="open = true">Open Drawer</px-button>
<px-drawer v-model="open">
<p>Main page content</p>
<template #sidebar>
<p>Sidebar content goes here.</p>
</template>
</px-drawer>
</div>
</template>
<script setup lang="ts">
import { ref } from 'vue';
const open = ref(false);
</script>Placement
Use placement to slide the drawer from the left or right edge.
<template>
<div class="demo-drawer">
<px-button @click="leftOpen = true">Left (default)</px-button>
<px-button @click="rightOpen = true">Right</px-button>
<px-drawer v-model="leftOpen" placement="left">
<template #sidebar>
<p>Left sidebar content</p>
</template>
</px-drawer>
<px-drawer v-model="rightOpen" placement="right">
<template #sidebar>
<p>Right sidebar content</p>
</template>
</px-drawer>
</div>
</template>
<script setup lang="ts">
import { ref } from 'vue';
const leftOpen = ref(false);
const rightOpen = ref(false);
</script>
<style scoped>
.demo-drawer {
display: flex;
gap: 12px;
}
</style>Custom Size
Use size to set the drawer width. Accepts any CSS width value.
<template>
<div class="demo-drawer">
<px-button @click="open200 = true">200px</px-button>
<px-button @click="open50 = true">50%</px-button>
<px-drawer v-model="open200" size="200px">
<template #sidebar>
<p>Narrow drawer (200px)</p>
</template>
</px-drawer>
<px-drawer v-model="open50" size="50%">
<template #sidebar>
<p>Wide drawer (50%)</p>
</template>
</px-drawer>
</div>
</template>
<script setup lang="ts">
import { ref } from 'vue';
const open200 = ref(false);
const open50 = ref(false);
</script>
<style scoped>
.demo-drawer {
display: flex;
gap: 12px;
}
</style>Overlay
Control the backdrop overlay with show-overlay and close-on-click-overlay.
<template>
<div class="demo-drawer">
<px-button @click="withOverlay = true">With Overlay</px-button>
<px-button @click="noOverlay = true">No Overlay</px-button>
<px-button @click="noClose = true">No Close on Overlay</px-button>
<px-drawer v-model="withOverlay">
<template #sidebar>
<p>Click overlay to close</p>
</template>
</px-drawer>
<px-drawer v-model="noOverlay" :show-overlay="false">
<template #sidebar>
<p>No overlay background</p>
<px-button @click="noOverlay = false">Close</px-button>
</template>
</px-drawer>
<px-drawer v-model="noClose" :close-on-click-overlay="false">
<template #sidebar>
<p>Overlay click won't close</p>
<px-button @click="noClose = false">Close</px-button>
</template>
</px-drawer>
</div>
</template>
<script setup lang="ts">
import { ref } from 'vue';
const withOverlay = ref(false);
const noOverlay = ref(false);
const noClose = ref(false);
</script>
<style scoped>
.demo-drawer {
display: flex;
gap: 12px;
flex-wrap: wrap;
}
</style>Title
Use the title prop to render a header with a pixel-dashed divider.
<template>
<div>
<px-button @click="open = true">Drawer with Title</px-button>
<px-drawer v-model="open" title="Settings">
<template #sidebar>
<p>The header shows a pixel-dashed divider below the title.</p>
</template>
</px-drawer>
</div>
</template>
<script setup lang="ts">
import { ref } from 'vue';
const open = ref(false);
</script>Disable Escape Close
Set close-on-esc to false to prevent the drawer from closing on Escape key press.
<template>
<div>
<px-button @click="open = true">Escape Disabled</px-button>
<px-drawer v-model="open" :close-on-esc="false">
<template #sidebar>
<p>Press Escape — nothing happens.</p>
<px-button @click="open = false">Close Manually</px-button>
</template>
</px-drawer>
</div>
</template>
<script setup lang="ts">
import { ref } from 'vue';
const open = ref(false);
</script>