Skip to main content
Browse docs

Marwes documentation

Drawer

Dialog-adjacent panel component with left/right placement, size variants, optional scrim, optional footer, and shared dialog semantics across adapters.

What this family solves

Dialog-adjacent panel component with left/right placement, size variants, optional scrim, optional footer, and shared dialog semantics across adapters.

Use when

  • The UI needs a side panel for contextual details, navigation, filters, or secondary workflows.
  • The panel can provide a truthful aria-label or aria-labelledby reference.
  • The product owns open state, close behavior, and focus return around the drawer.

Avoid when

  • The interaction is a blocking confirmation; use Dialog instead.
  • The product cannot provide focus management for modal drawer usage.
  • The content is short inline help; use Tooltip or a simpler disclosure instead.

Public imports

Choose an adapter in the verified examples. The inventory below reflects each framework package exactly.

React — @marwes-ui/react

Component

Drawer

Types

DrawerPlacement, DrawerProps, DrawerSize

Vue — @marwes-ui/vue

Component

Drawer

Types

DrawerPlacement, DrawerProps, DrawerSize

Svelte — @marwes-ui/svelte

Component

Drawer

Types

DrawerPlacement, DrawerProps, DrawerSize

Verified minimal examples

These examples come from the same fixtures verified by the repository checks.

React

import { Button, ButtonVariant, DialogModal, Drawer, Paragraph } from "@marwes-ui/react"
import { useState } from "react"

export function Example() {
  const [dialogOpen, setDialogOpen] = useState(false)
  const [drawerOpen, setDrawerOpen] = useState(false)

  return (
    <>
      <Button variant={ButtonVariant.primary} onClick={() => setDialogOpen(true)}>
        Open dialog →
      </Button>
      <Button variant={ButtonVariant.secondary} onClick={() => setDrawerOpen(true)}>
        Open drawer →
      </Button>

      <DialogModal
        open={dialogOpen}
        onOpenChange={setDialogOpen}
        title="Dialog title"
        description="This is a dialog component."
        footer={
          <Button variant={ButtonVariant.primary} onClick={() => setDialogOpen(false)}>
            Close
          </Button>
        }
      >
        <Paragraph>Dialog content goes here.</Paragraph>
      </DialogModal>

      {drawerOpen && (
        <Drawer
          modal
          title="Drawer"
          size="medium"
          placement="right"
          onClose={() => setDrawerOpen(false)}
          footer={
            <Button variant={ButtonVariant.secondary} onClick={() => setDrawerOpen(false)}>
              Close drawer
            </Button>
          }
        >
          <p>Drawer content goes here.</p>
        </Drawer>
      )}
    </>
  )
}

Vue

<script setup lang="ts">
import { ref } from "vue"
import { Button, DialogModal, Drawer, Paragraph } from "@marwes-ui/vue"

const dialogOpen = ref(false)
const drawerOpen = ref(false)
</script>

<template>
  <Button variant="primary" @click="dialogOpen = true">Open dialog →</Button>
  <Button variant="secondary" @click="drawerOpen = true">Open drawer →</Button>

  <DialogModal
    v-model:open="dialogOpen"
    title="Dialog title"
    description="This is a dialog component."
  >
    <Paragraph>Dialog content goes here.</Paragraph>
    <template #footer>
      <Button variant="primary" @click="dialogOpen = false">Close</Button>
    </template>
  </DialogModal>

  <Drawer
    v-if="drawerOpen"
    modal
    title="Drawer"
    size="medium"
    placement="right"
    @close="drawerOpen = false"
  >
    <p>Drawer content goes here.</p>
    <template #footer>
      <Button variant="secondary" @click="drawerOpen = false">Close drawer</Button>
    </template>
  </Drawer>
</template>

Svelte

<script lang="ts">
  import { Button, DialogModal, Drawer, Paragraph } from "@marwes-ui/svelte"

  let dialogOpen = $state(false)
  let drawerOpen = $state(false)
</script>

<Button variant="primary" onclick={() => (dialogOpen = true)}>Open dialog →</Button>
<Button variant="secondary" onclick={() => (drawerOpen = true)}>Open drawer →</Button>

<DialogModal
  bind:open={dialogOpen}
  title="Dialog title"
  description="This is a dialog component."
>
  <Paragraph>Dialog content goes here.</Paragraph>
  {#snippet footer()}
    <Button variant="primary" onclick={() => (dialogOpen = false)}>Close</Button>
  {/snippet}
</DialogModal>

{#if drawerOpen}
  <Drawer
    modal
    title="Drawer"
    size="medium"
    placement="right"
    onclose={() => (drawerOpen = false)}
  >
    <p>Drawer content goes here.</p>
    {#snippet footer()}
      <Button variant="secondary" onclick={() => (drawerOpen = false)}>Close drawer</Button>
    {/snippet}
  </Drawer>
{/if}

Accessibility requirements

  • Conditional mounting: Mount Drawer only while open; do not leave a hidden instance competing for focus.
  • Placement and modal behavior: Verify the chosen placement and modal behavior match how the surrounding page is used.
  • Focus and escape review: Test focus entry, focus return, dismissal, and escape-key behavior in context.
  • Manual review boundary: Keyboard focus trap, Escape handling, and focus return in real product compositions.
  • Manual review 2: Screen-reader announcement of drawer title/description in modal and non-modal contexts.
  • Manual review 3: Visual review against the synced light and dark Figma drawer frames.

Theming

Drawer uses Marwes preset CSS and theme variables. Customize it through the theme passed to MarwesProvider; do not add a second component stylesheet. See the theming guide for configuration and token details.

Resources