Packages by abhivarde.in

Svelte Drawer

A drawer component for Svelte 5, inspired by Vaul.

GitHub

Installation

npm install @abhivarde/svelte-drawer

Usage

Basic setup with a bottom drawer.

import { Drawer, DrawerOverlay, DrawerContent } from '@abhivarde/svelte-drawer';

<script>
  let open = $state(false);
</script>

<button onclick={() => open = true}>Open Drawer</button>

<Drawer bind:open>
  <DrawerOverlay />
  <DrawerContent class="bg-white rounded-t-lg p-6">
    <div class="mx-auto w-12 h-1.5 rounded-full bg-gray-300 mb-8" />
    <h2 class="text-lg font-medium">Drawer Title</h2>
    <p class="text-gray-600">Drawer content goes here.</p>
  </DrawerContent>
</Drawer>

Position

Change direction with the direction prop.

<Drawer direction="bottom"> <!-- Default: from bottom --> </Drawer>
<Drawer direction="top"> <!-- From top --> </Drawer>
<Drawer direction="left"> <!-- From left --> </Drawer>
<Drawer direction="right"> <!-- From right --> </Drawer>

Examples

Default Drawer

<Drawer bind:open={defaultOpen}>
  <DrawerOverlay />
  <DrawerContent class="bg-gray-100 flex flex-col rounded-t-[10px] mt-24 h-fit fixed bottom-0 left-0 right-0 outline-none">
    <div class="p-4 bg-white rounded-t-[10px] flex-1">
      <div aria-hidden="true" class="mx-auto w-12 h-1.5 flex-shrink-0 rounded-full bg-gray-300 mb-8"></div>
      <div class="max-w-md mx-auto">
        <h2 class="font-medium mb-4 text-gray-900">Drawer for Svelte.</h2>
        <p class="text-gray-600 mb-2">This component can be used as a Dialog replacement on mobile and tablet devices.</p>
        <p class="text-gray-600 mb-2">This is the simplest setup.</p>
      </div>
    </div>
    <div class="p-4 bg-gray-100 border-t border-gray-200 mt-auto">
      <div class="flex gap-6 justify-end max-w-md mx-auto">
        <a class="text-xs text-gray-600 flex items-center gap-0.5 hover:text-gray-900" href="https://github.com/AbhiVarde/svelte-drawer" target="_blank" rel="noopener noreferrer">
          GitHub {@html externalLinkIcon}
        </a>
        <a class="text-xs text-gray-600 flex items-center gap-0.5 hover:text-gray-900" href="https://x.com/varde_abhi" target="_blank" rel="noopener noreferrer">
          X {@html externalLinkIcon}
        </a>
      </div>
    </div>
  </DrawerContent>
</Drawer>

Side Drawer

<Drawer bind:open={sideOpen} direction="right">
  <DrawerOverlay />
  <DrawerContent class="right-2 top-2 bottom-2 fixed outline-none w-[310px] flex">
    <div class="bg-zinc-50 h-full w-full grow p-5 flex flex-col rounded-[16px]">
      <div class="max-w-md mx-auto">
        <h2 class="font-medium mb-2 text-zinc-900">It supports all directions.</h2>
        <p class="text-zinc-600 mb-2">This drawer is positioned on the right side.</p>
      </div>
      <div class="mt-auto pt-8">
        <div class="flex gap-6 justify-center">
          <a class="text-xs text-zinc-600 flex items-center gap-0.5 hover:text-zinc-900" href="https://github.com/AbhiVarde/svelte-drawer" target="_blank" rel="noopener noreferrer">
            GitHub {@html externalLinkIcon}
          </a>
          <a class="text-xs text-zinc-600 flex items-center gap-0.5 hover:text-zinc-900" href="https://x.com/varde_abhi" target="_blank" rel="noopener noreferrer">
            X {@html externalLinkIcon}
          </a>
        </div>
      </div>
    </div>
  </DrawerContent>
</Drawer>

Nested Drawers

<Drawer bind:open={nested1Open}>
  <DrawerOverlay />
  <DrawerContent class="bg-gray-100 flex flex-col rounded-t-[10px] h-full mt-24 lg:h-fit max-h-[96%] fixed bottom-0 left-0 right-0">
    <div class="p-4 bg-white rounded-t-[10px] flex-1">
      <div class="mx-auto w-12 h-1.5 flex-shrink-0 rounded-full bg-gray-300 mb-8"></div>
      <div class="max-w-md mx-auto">
        <h2 class="font-medium mb-4 text-gray-900">Nested Drawers.</h2>
        <p class="text-gray-600 mb-2">Nesting drawers creates a stacking effect.</p>
        <p class="text-gray-600 mb-4">Open the second drawer to see it in action.</p>
        <button onclick={() => nested2Open = true} class="rounded-md w-full bg-gray-900 px-4 py-2.5 text-sm font-medium text-white hover:bg-gray-800">
          Open Second Drawer
        </button>
      </div>
    </div>
    <div class="p-4 bg-gray-100 border-t border-gray-200 mt-auto">
      <div class="flex gap-6 justify-end max-w-md mx-auto">
        <a class="text-xs text-gray-600 flex items-center gap-0.5 hover:text-gray-900" href="https://github.com/AbhiVarde/svelte-drawer" target="_blank" rel="noopener noreferrer">
          GitHub {@html externalLinkIcon}
        </a>
        <a class="text-xs text-gray-600 flex items-center gap-0.5 hover:text-gray-900" href="https://x.com/varde_abhi" target="_blank" rel="noopener noreferrer">
          X {@html externalLinkIcon}
        </a>
      </div>
    </div>
  </DrawerContent>
</Drawer>

<Drawer bind:open={nested2Open}>
  <DrawerOverlay class="z-[60]" />
  <DrawerContent class="bg-gray-100 flex flex-col rounded-t-[10px] h-full mt-24 max-h-[94%] fixed bottom-0 left-0 right-0 z-[70]">
    <div class="p-4 bg-white rounded-t-[10px] flex-1">
      <div class="mx-auto w-12 h-1.5 flex-shrink-0 rounded-full bg-gray-300 mb-8"></div>
      <div class="max-w-md mx-auto">
        <h2 class="font-medium mb-4 text-gray-900">This drawer is nested.</h2>
        <p class="text-gray-600 mb-2">Pull down to see the scaling effect.</p>
      </div>
    </div>
    <div class="p-4 bg-gray-100 border-t border-gray-200 mt-auto">
      <div class="flex gap-6 justify-end max-w-md mx-auto">
        <a class="text-xs text-gray-600 flex items-center gap-0.5 hover:text-gray-900" href="https://github.com/AbhiVarde/svelte-drawer" target="_blank" rel="noopener noreferrer">
          GitHub {@html externalLinkIcon}
        </a>
        <a class="text-xs text-gray-600 flex items-center gap-0.5 hover:text-gray-900" href="https://x.com/varde_abhi" target="_blank" rel="noopener noreferrer">
          X {@html externalLinkIcon}
        </a>
      </div>
    </div>
  </DrawerContent>
</Drawer>

Scrollable Drawer

<Drawer bind:open={scrollableOpen}>
  <DrawerOverlay />
  <DrawerContent class="bg-gray-100 flex flex-col rounded-t-[10px] mt-24 h-[80%] lg:h-[320px] fixed bottom-0 left-0 right-0 outline-none">
    <div class="p-4 bg-white rounded-t-[10px] flex-1 overflow-y-auto">
      <div class="max-w-md mx-auto space-y-4">
        <div aria-hidden="true" class="mx-auto w-12 h-1.5 flex-shrink-0 rounded-full bg-gray-300 mb-8"></div>
        <h2 class="font-medium mb-4 text-gray-900">Scrollable Drawer</h2>
        <!-- Long content here -->
      </div>
    </div>
    <div class="p-4 bg-gray-100 border-t border-gray-200 mt-auto">
      <div class="flex gap-6 justify-end max-w-md mx-auto">
        <a class="text-xs text-gray-600 flex items-center gap-0.5 hover:text-gray-900" href="https://github.com/AbhiVarde/svelte-drawer" target="_blank" rel="noopener noreferrer">
          GitHub {@html externalLinkIcon}
        </a>
        <a class="text-xs text-gray-600 flex items-center gap-0.5 hover:text-gray-900" href="https://x.com/varde_abhi" target="_blank" rel="noopener noreferrer">
          X {@html externalLinkIcon}
        </a>
      </div>
    </div>
  </DrawerContent>
</Drawer>

Controlled Drawer

<Drawer bind:open={controlledOpen} onOpenChange={(isOpen) => console.log('Drawer is now:', isOpen ? 'open' : 'closed')}>
  <DrawerOverlay />
  <DrawerContent class="bg-gray-100 flex flex-col rounded-t-[10px] mt-24 h-fit fixed bottom-0 left-0 right-0 outline-none">
    <div class="p-4 bg-white rounded-t-[10px] flex-1">
      <div class="mx-auto w-12 h-1.5 flex-shrink-0 rounded-full bg-gray-300 mb-8"></div>
      <div class="max-w-md mx-auto">
        <h2 class="font-medium mb-4 text-gray-900">A controlled drawer.</h2>
        <p class="text-gray-600 mb-2">Control the state externally while still reacting to user gestures via onOpenChange.</p>
      </div>
    </div>
    <div class="p-4 bg-gray-100 border-t border-gray-200 mt-auto">
      <div class="flex gap-6 justify-end max-w-md mx-auto">
        <a class="text-xs text-gray-600 flex items-center gap-0.5 hover:text-gray-900" href="https://github.com/AbhiVarde/svelte-drawer" target="_blank" rel="noopener noreferrer">
          GitHub {@html externalLinkIcon}
        </a>
        <a class="text-xs text-gray-600 flex items-center gap-0.5 hover:text-gray-900" href="https://x.com/varde_abhi" target="_blank" rel="noopener noreferrer">
          X {@html externalLinkIcon}
        </a>
      </div>
    </div>
  </DrawerContent>
</Drawer>