<arc-drawer> Overview
Guidelines
When to use
- Use for mobile navigation menus that slide in from the left edge
- Use for filter or settings panels in data-heavy dashboards
- Provide a clear, short heading that tells the user what the panel contains
- Keep the drawer width reasonable — the default 300px works for most navigation use cases
- Use `position="right"` for detail views and contextual information panels
- Always listen for the `arc-close` event to keep your open state in sync
When not to use
- Do not use a Drawer for critical confirmations — use Modal instead
- Do not nest a Drawer inside another Drawer
- Do not put complex multi-step forms in a Drawer — consider a full page or Modal
- Do not auto-open a Drawer on page load without a clear user-initiated trigger
- Do not remove the backdrop — users expect click-outside-to-close behavior
- Do not place unrelated content in the drawer heading area — keep it for the title and close button
Features
- Slides in from the left or right edge via CSS transforms with configurable `position` prop
- Semi-transparent backdrop overlay dims the page and captures click-to-close
- Escape key dismissal with automatic keyboard listener management
- Body scroll lock while open prevents background content interaction
- Built-in header bar with heading text and close button
- Scrollable body region for long content like navigation trees or filter forms
- Fires `arc-close` custom event on any dismiss action for state synchronization
- Max-width capped at 85vw so the drawer never fully obscures the page
- CSS custom property theming via `--bg-surface`, `--border-subtle`, and `--text-primary`
- Accessible with `role="dialog"`, `aria-modal="true"`, and `aria-label` from heading
Preview
Usage
This component requires JavaScript. No pure HTML/CSS version is available — use the Web Component directly or a framework wrapper.
<arc-button id="open-nav-drawer">Menu</arc-button>
<arc-drawer id="nav-drawer" heading="Navigation" position="left">
<nav style="display:flex; flex-direction:column; gap:4px; padding:8px;">
<a href="/dashboard" style="padding:10px 12px; border-radius:6px; color:var(--text-primary); text-decoration:none;">Dashboard</a>
<a href="/projects" style="padding:10px 12px; border-radius:6px; color:var(--text-secondary); text-decoration:none;">Projects</a>
<a href="/activity" style="padding:10px 12px; border-radius:6px; color:var(--text-secondary); text-decoration:none;">Activity</a>
<a href="/settings" style="padding:10px 12px; border-radius:6px; color:var(--text-secondary); text-decoration:none;">Settings</a>
</nav>
</arc-drawer>
<script>
const openBtn = document.querySelector('#open-nav-drawer');
const drawer = document.querySelector('#nav-drawer');
openBtn.addEventListener('click', () => { drawer.open = true; });
drawer.addEventListener('arc-close', () => { drawer.open = false; });
</script> import { useState } from 'react';
import { Button, Drawer } from '@arclux/arc-ui-react';
function MobileNav() {
const [open, setOpen] = useState(false);
return (
<>
<Button onClick={() => setOpen(true)}>Menu</Button>
<Drawer open={open} heading="Navigation" position="left" onArcClose={() => setOpen(false)}>
<nav style={{ display: 'flex', flexDirection: 'column', gap: 4, padding: 8 }}>
<a href="/dashboard">Dashboard</a>
<a href="/projects">Projects</a>
<a href="/activity">Activity</a>
<a href="/settings">Settings</a>
</nav>
</Drawer>
</>
);
} <script setup>
import { ref } from 'vue';
import { Button, Drawer } from '@arclux/arc-ui-vue';
const open = ref(false);
</script>
<template>
<Button @click="open = true">Menu</Button>
<Drawer :open="open" heading="Navigation" position="left" @arc-close="open = false">
<nav style="display:flex; flex-direction:column; gap:4px; padding:8px;">
<a href="/dashboard">Dashboard</a>
<a href="/projects">Projects</a>
<a href="/activity">Activity</a>
<a href="/settings">Settings</a>
</nav>
</Drawer>
</template> <script>
import { Button, Drawer } from '@arclux/arc-ui-svelte';
let open = $state(false);
</script>
<Button onclick={() => open = true}>Menu</Button>
<Drawer {open} heading="Navigation" position="left" on:arc-close={() => open = false}>
<nav style="display:flex; flex-direction:column; gap:4px; padding:8px;">
<a href="/dashboard">Dashboard</a>
<a href="/projects">Projects</a>
<a href="/activity">Activity</a>
<a href="/settings">Settings</a>
</nav>
</Drawer> import { Component } from '@angular/core';
import { Button, Drawer } from '@arclux/arc-ui-angular';
@Component({
imports: [Button, Drawer],
template: `
<Button (click)="open = true">Menu</Button>
<Drawer [open]="open" heading="Navigation" position="left" (arcClose)="open = false">
<nav style="display:flex; flex-direction:column; gap:4px; padding:8px;">
<a href="/dashboard">Dashboard</a>
<a href="/projects">Projects</a>
<a href="/activity">Activity</a>
<a href="/settings">Settings</a>
</nav>
</Drawer>
`,
})
export class MobileNavComponent {
open = false;
} import { createSignal } from 'solid-js';
import { Button, Drawer } from '@arclux/arc-ui-solid';
function MobileNav() {
const [open, setOpen] = createSignal(false);
return (
<>
<Button onClick={() => setOpen(true)}>Menu</Button>
<Drawer open={open()} heading="Navigation" position="left" onArcClose={() => setOpen(false)}>
<nav style={{ display: 'flex', 'flex-direction': 'column', gap: '4px', padding: '8px' }}>
<a href="/dashboard">Dashboard</a>
<a href="/projects">Projects</a>
<a href="/activity">Activity</a>
<a href="/settings">Settings</a>
</nav>
</Drawer>
</>
);
} import { useState } from 'preact/hooks';
import { Button, Drawer } from '@arclux/arc-ui-preact';
function MobileNav() {
const [open, setOpen] = useState(false);
return (
<>
<Button onClick={() => setOpen(true)}>Menu</Button>
<Drawer open={open} heading="Navigation" position="left" onArcClose={() => setOpen(false)}>
<nav style={{ display: 'flex', flexDirection: 'column', gap: 4, padding: 8 }}>
<a href="/dashboard">Dashboard</a>
<a href="/projects">Projects</a>
<a href="/activity">Activity</a>
<a href="/settings">Settings</a>
</nav>
</Drawer>
</>
);
} API
| Prop | Type | Default | Description |
|---|---|---|---|
open | boolean | false | Controls the visible state of the drawer. Set to `true` to slide the panel into view and activate the backdrop; set to `false` to run the exit animation, remove the backdrop, and restore body scroll. |
heading | string | '' | Text displayed in the drawer header bar. Also used as the `aria-label` for the dialog panel, ensuring screen readers announce the panel purpose when it opens. |
position | 'left' | 'right' | 'left' | Which edge of the viewport the drawer slides in from. Use `left` for primary navigation menus and `right` for contextual detail panels, filter sidebars, or settings trays. |
Events
| Event | Description |
|---|---|
arc-close | Fired when the drawer closes via backdrop click or escape key |
See Also
- Modal General-purpose focus-trapping overlay with backdrop blur, slide-up animation, and ESC-to-close behavior for forms, settings, and rich content that needs full user attention.
- Sheet A sliding overlay panel that emerges from the bottom or right edge of the viewport, with a blurred backdrop, header, scrollable body, and footer slot.
- Sidebar Collapsible navigation sidebar with grouped sections, heading labels, and active link highlighting. Ideal for documentation sites, admin panels, and any layout that needs persistent vertical navigation.