Drawer
Side panels and form surfaces
Usage
Basic Drawer
The common drawer pattern, with a confirmation dialog above it. Tab stays in the confirmation and Escape closes only the confirmation.
Best Practices
- Use Drawer for long forms, audit details, permission matrices, and flows that need footer actions.
- Keep
titlemeaningful even whenshowHeader=false; it becomes the dialog's accessible fallback label. - Prefer
sizeandfull; keepwidthonly for old call sites that have not migrated yet. - Use
mobileAdapt=falseonly when preserving side direction is more important than bottom-sheet ergonomics on small screens.
API Reference
Props
| Property | Type | Default | Description |
|---|---|---|---|
| visible | Controls drawer visibility | ||
| title | Title text | ||
| size | Active-axis size; width for left/right and height for top/bottom; numbers are px and full maps to 100% | ||
| full | Open at 100% on the active axis, equivalent to size="full" | ||
| width | - | Deprecated compatibility alias; use size instead | |
| direction | Slide-in direction | ||
| showHeader | Render the header area | ||
| showFooter | Render the footer slot area | ||
| showClose | Show close button | ||
| closeOnClickMask | Close on mask click | ||
| closeOnPressEscape | Close on Escape key | ||
| maskEffect | Mask visual effect | ||
| panelTransparent | Make the panel translucent so the back layer shows through | ||
| mobileAdapt | Force bottom direction on mobile viewport | ||
| zIndex | - | Custom z-index. When unset the runtime z-index manager assigns one (seeded at `10000`, incremented per drawer); set it manually only to coexist with externally fixed layers. | |
| lazy | Defer rendering slot content until the drawer first opens. The panel itself stays mounted, so the slide-out animation is unaffected; content is kept alive after the first open, so reopening never re-runs child setup. Set `false` when a child must mount eagerly. |
Events
| Property | Type | Default | Description |
|---|---|---|---|
| update:visible | - | Emitted on visibility change | |
| open | - | Emitted when opened | |
| close | - | Emitted when closed |
Slots
| Property | Type | Default | Description |
|---|---|---|---|
| default | - | - | Main content |
| header | - | - | Custom header; slot props: { close, title, titleId } |
| footer | - | - | Footer area; slot props: { close } |
Direction
Drawers support left, right, top, and bottom. Mobile viewports adapt to bottom by default unless mobile-adapt="false" is set.
Direction
Four-direction drawers. The size prop maps to width for left/right and height for top/bottom.
Size and Fullscreen
Size and Fullscreen
Use the unified size prop for the active axis: width for left/right, height for top/bottom. It supports px, rem, percentages, any CSS length, and full. You can also use the more discoverable boolean full prop, equivalent to size="full". width remains as a compatibility alias for old code.
Header / Footer Slots and Mask
Use the header / footer slots to customize the chrome, or disable them with show-header / show-footer. Built-in header/footer separators reuse TxDivider. mask-effect supports blur, opacity, and transparent; panel-transparent lets the panel surface show content behind it.
Custom header / footer slots + mask effect
Compatibility example: use the footer slot to add action buttons.
<template>
<TxDrawer v-model:visible="visible" title="Form">
<form>
<input type="text" placeholder="Name" />
</form>
<template #footer>
<TxButton @click="visible = false">Cancel</TxButton>
<TxButton type="primary" @click="handleSave">Save</TxButton>
</template>
</TxDrawer>
</template>
Close Behavior
<template>
<!-- Disable mask click -->
<TxDrawer
v-model:visible="visible"
title="Persistent"
:close-on-click-mask="false"
>
<p>Close via the button only.</p>
</TxDrawer>
<!-- Disable Escape close -->
<TxDrawer
v-model:visible="visible2"
title="Disable Escape"
:close-on-press-escape="false"
>
<p>Escape key won't close this drawer.</p>
</TxDrawer>
</template>
Events
<template>
<TxDrawer
v-model:visible="visible"
title="Event Demo"
@open="handleOpen"
@close="handleClose"
>
<p>Content</p>
</TxDrawer>
</template>
Dashboard Navigation Composition
Admin pages should not put every setting into one large form. Use TxTabs for first-level sections, TxDropdownMenu for lightweight actions in the current section, TxPopover for short explanations, and TxDrawer for dense configuration.
Dashboard navigation shell
A screenshot-verified Tabs / DropdownMenu / Popover / Drawer composition for Dashboard settings pages.
Overview
- The drawer root exposes
role="dialog"andaria-modal="true"; with a header it links the title through instance-scopedaria-labelledby, and without a header it falls back totitleasaria-label. - Opening the drawer focuses the drawer root; hiding or unmounting restores focus to the element that was active before opening.
- The close button, mask click, and Escape close paths emit
update:visible(false)andcloseby default;closeOnClickMask=falseandcloseOnPressEscape=falseblock their respective paths. - Keys already handled by another control, or originating in another modal dialog, are not handled again by the drawer. A confirmation above the drawer owns Tab, Shift+Tab and Escape without a page-level CSS-class or body-event guard.
showClose=falseremoves the default close button without changing mask or Escape behavior.mobileAdapt=trueforces bottom direction on mobile; set:mobile-adapt="false"to preserve the requested direction.
Technologies
- Component source:
packages/tuffex/packages/components/src/drawer/src/TxDrawer.vue. - Types:
packages/tuffex/packages/components/src/drawer/src/types.ts. - Verified coverage: Coverage:
packages/tuffex/packages/components/src/drawer/__tests__/drawer.test.tsverifies visibility emits, focus restoration, ARIA labeling, close controls, size resolution, mobile adaptation, and separator rendering.
- The drawer root already exposes
role="dialog"/aria-modal="true"and title linkage; form fields inside still need explicit labels. - Opening stores the previously focused element and restores it on hide/unmount; avoid manually stealing focus from outside.
- Dashboard settings pages should place long forms, permission matrices, and audit detail in Drawer rather than Popover.
- Built-in header/footer separators come from
TxDivider, avoiding duplicated border styling.