Vaul Vue Unstyled Drawer

0.4.1 · active · verified Sun Apr 19

Vaul Vue is an unstyled, headless drawer component specifically designed for Vue 3 applications, serving as a modern and highly customizable replacement for traditional dialogs and modals, particularly optimized for tablet and mobile devices. It stands at version 0.4.1 and demonstrates an active development cadence with frequent patch releases addressing bug fixes and occasional minor releases introducing new features or significant architectural refactorings. This library is a feature-complete port of Emil Kowalski's original Vaul library, which was built for React, ensuring a mature and well-tested interaction model. Under the hood, Vaul Vue leverages Reka UI's Dialog primitive, providing a robust foundation for accessibility and core interaction logic. Its unstyled nature is a key differentiator, granting developers complete control over the visual presentation to seamlessly integrate with any design system. The headless architecture ensures that essential accessibility features are provided out-of-the-box, without dictating styling. Key features include highly customizable snap points, support for various drag directions, and a comprehensive set of primitives (`DrawerRoot`, `DrawerTrigger`, `DrawerPortal`, `DrawerOverlay`, `DrawerContent`) that enable building bespoke drawer experiences tailored to specific application needs, making it a powerful tool for responsive web design.

Common errors

Warnings

Install

Imports

Quickstart

Demonstrates a basic Vaul Vue drawer with snap points, custom styling (using Tailwind-like classes), and a trigger button, including the necessary CSS import.

<script setup lang="ts">
import { DrawerContent, DrawerOverlay, DrawerPortal, DrawerRoot, DrawerTrigger } from 'vaul-vue'
import 'vaul-vue/dist/style.css' // Important: import Vaul Vue's default styles
</script>

<template>
  <DrawerRoot :snap-points="[0.5, 0.8]" :open="true"> <!-- Added :open for demonstration -->
    <DrawerTrigger as-child>
      <button class="px-4 py-2 bg-blue-500 text-white rounded hover:bg-blue-600">Open Drawer</button>
    </DrawerTrigger>
    <DrawerPortal>
      <!-- Overlay for background dimming when drawer is open -->
      <DrawerOverlay class="fixed inset-0 bg-black/40 z-40" />
      <DrawerContent class="bg-white flex flex-col rounded-t-[10px] h-full mt-24 fixed bottom-0 left-0 right-0 max-h-[96%] max-w-md mx-auto z-50">
        <div class="mx-auto w-12 h-1.5 flex-shrink-0 rounded-full bg-gray-300 my-3" />
        <div class="flex-1 p-4 overflow-y-auto">
          <h2 class="text-xl font-semibold text-gray-800 mb-2">Welcome to Vaul Vue!</h2>
          <p class="text-gray-700 leading-relaxed">
            This is an unstyled, headless drawer component for Vue 3. It's designed to be a flexible
            and accessible replacement for dialogs and modals on mobile and tablet devices.
            You can drag it up or down to adjust its position or dismiss it.
            It uses <a href="https://www.reka-ui.com/docs/components/dialog" target="_blank" class="text-blue-600 hover:underline">Reka UI's Dialog primitive</a>
            under the hood for robust accessibility.
          </p>
          <p class="text-gray-700 leading-relaxed mt-4">
            Feel free to customize all aspects of its appearance with your own CSS or utility classes.
            The `snap-points` prop allows you to define specific heights where the drawer can rest.
          </p>
          <div class="mt-8">
            <h3 class="font-medium text-gray-800 mb-2">Key Features:</h3>
            <ul class="list-disc list-inside text-gray-700">
              <li>Unstyled & Headless</li>
              <li>Mobile-first interaction</li>
              <li>Customizable snap points</li>
              <li>Uses Reka UI for accessibility</li>
            </ul>
          </div>
          <p class="text-gray-500 text-sm mt-8">Drag this drawer down to close it, or click the overlay.</p>
        </div>
        <div class="border-t border-gray-200 p-4 flex justify-end">
          <button class="px-4 py-2 bg-red-500 text-white rounded hover:bg-red-600">Close Drawer</button>
        </div>
      </DrawerContent>
    </DrawerPortal>
  </DrawerRoot>
</template>

view raw JSON →