Skip to content
ARC UI ARC Reactive Components
Docs Components Tokens Synthesizer
v2.1.0
Getting Started Frameworks Design Tokens Theming Theme Synthesizer Accessibility Browser Support Changelog Contributing All Components App ShellAspect GridAuth ShellCenterClusterContainerDashboard GridDockFloat BarInsetMasonryPage HeaderPage LayoutResizableResponsive SwitcherSectionSettings LayoutSplit PaneStatus BarStickyToolbar Anchor NavBottom NavBreadcrumbBreadcrumb MenuCommand BarDrawerFooterLinkNavigation MenuPage IndicatorPaginationRailScroll IndicatorScroll SpyScroll To TopSidebarSkip LinkSpeed DialStepper NavTabsTop BarTree View AccordionAspect RatioAvatarAvatar GroupCalloutCardCarouselCollapsibleColor SwatchCTA BannerDividerEmpty StateFeature CardIconImageInfinite ScrollMarqueeScroll AreaSeparatorSkeletonSpinnerStackVirtual List Animated NumberBadgeComparisonCountdown TimerData TableDescription ListDiffKey ValueListMeterSparklineStatStepperTableTagTimelineValue Card BlockquoteCode BlockGradient TextHighlightKbdMarkdownNumber FormatProseTextTime AgoTruncateTypewriter ButtonButton GroupCalendarCheckboxChipColor PickerComboboxCopy ButtonDate PickerFieldsetFile UploadFormHotkeyIcon ButtonInputInput GroupLabelMulti SelectNumber InputOTP InputPin InputRadio GroupRange SliderRatingSearchSegmented ControlSelectSliderSortable ListSwitch GroupTextareaTheme ToggleTime PickerToggle AlertAnnouncementBannerCommand PaletteConfirmConnection StatusContext MenuDialogDropdown MenuGuided TourHover CardInline MessageLoading OverlayModalNotification PanelPopoverProgressProgress ToastSheetSnackbarSpotlightToastTooltip
Components Drawer
navigation interactive
<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