Drawer

A slide-out panel that can appear from any edge of the screen. Perfect for mobile-optimized navigation, forms, and detail views.

Requires JavaScript

Installation

Add the component to your project:

rails generate shadcn:component drawer

Usage

<%= render Shadcn::DrawerComponent.new do |drawer| %>
  <% drawer.with_trigger do %>
    <%= render Shadcn::ButtonComponent.new(variant: :outline) do %>Open Drawer<% end %>
  <% end %>
  <% drawer.with_body do |content| %>
    <% content.with_header do |header| %>
      <% header.with_title { "Drawer Title" } %>
      <% header.with_description { "Drawer description here." } %>
    <% end %>
    <div class="p-4">
      <p>Drawer body content goes here.</p>
    </div>
    <% content.with_footer do %>
      <%= render Shadcn::ButtonComponent.new { "Save" } %>
    <% end %>
  <% end %>
<% end %>

Examples

Basic Drawer

<%= render Shadcn::DrawerComponent.new do |drawer| %>
  <% drawer.with_trigger do %>
    <%= render Shadcn::ButtonComponent.new(variant: :outline) do %>Basic Drawer<% end %>
  <% end %>
  <% drawer.with_body do |content| %>
    <% content.with_header do |header| %>
      <% header.with_title { "Are you sure?" } %>
      <% header.with_description { "This action cannot be undone." } %>
    <% end %>
    <% content.with_footer do %>
      <div class="flex gap-2 justify-end">
        <%= render Shadcn::ButtonComponent.new(variant: :outline, data: { action: "click->shadcn--drawer#close" }) { "Cancel" } %>
        <%= render Shadcn::ButtonComponent.new(variant: :destructive) { "Delete" } %>
      </div>
    <% end %>
  <% end %>
<% end %>

With Form

Drawers are perfect for forms and data entry on mobile devices.

<%= render Shadcn::DrawerComponent.new do |drawer| %>
  <% drawer.with_trigger do %>
    <%= render Shadcn::ButtonComponent.new do %>Edit Profile<% end %>
  <% end %>
  <% drawer.with_body do |content| %>
    <% content.with_header do |header| %>
      <% header.with_title { "Edit Profile" } %>
      <% header.with_description { "Make changes to your profile here." } %>
    <% end %>
    <div class="p-4 space-y-4">
      <div class="space-y-2">
        <%= render Shadcn::LabelComponent.new(for: "name") { "Name" } %>
        <%= render Shadcn::InputComponent.new(id: "name", value: "John Doe") %>
      </div>
      <div class="space-y-2">
        <%= render Shadcn::LabelComponent.new(for: "username") { "Username" } %>
        <%= render Shadcn::InputComponent.new(id: "username", value: "@johndoe") %>
      </div>
    </div>
    <% content.with_footer do %>
      <%= render Shadcn::ButtonComponent.new(type: "submit", class_name: "w-full") { "Save changes" } %>
    <% end %>
  <% end %>
<% end %>

Different Directions

Drawers can slide in from any edge: bottom (default), top, left, or right.

From Left

<%= render Shadcn::DrawerComponent.new(direction: :left) do |drawer| %>
  <% drawer.with_trigger do %>
    <%= render Shadcn::ButtonComponent.new(variant: :outline) do %>Open from Left<% end %>
  <% end %>
  <% drawer.with_body(direction: :left) do |content| %>
    <% content.with_header do |header| %>
      <% header.with_title { "Side Panel" } %>
      <% header.with_description { "Content slides in from the left." } %>
    <% end %>
    <div class="p-4 flex-1">
      <p>Drawer content here.</p>
    </div>
  <% end %>
<% end %>

From Right

<%= render Shadcn::DrawerComponent.new(direction: :right) do |drawer| %>
  <% drawer.with_trigger do %>
    <%= render Shadcn::ButtonComponent.new(variant: :outline) do %>Open from Right<% end %>
  <% end %>
  <% drawer.with_body(direction: :right) do |content| %>
    <% content.with_header do |header| %>
      <% header.with_title { "Side Panel" } %>
      <% header.with_description { "Content slides in from the right." } %>
    <% end %>
    <div class="p-4 flex-1">
      <p>Drawer content here.</p>
    </div>
  <% end %>
<% end %>

From Top

<%= render Shadcn::DrawerComponent.new(direction: :top) do |drawer| %>
  <% drawer.with_trigger do %>
    <%= render Shadcn::ButtonComponent.new(variant: :outline) do %>Open from Top<% end %>
  <% end %>
  <% drawer.with_body(direction: :top) do |content| %>
    <% content.with_header do |header| %>
      <% header.with_title { "Top Drawer" } %>
      <% header.with_description { "Content slides in from the top." } %>
    <% end %>
    <div class="p-4">
      <p>Drawer content here.</p>
    </div>
  <% end %>
<% end %>

Custom Close Action

Use data-action="click->shadcn--drawer#close" on any element to close the drawer.

API Reference

DrawerComponent

API Reference

Prop Type Default Description
open Boolean false Whether the drawer starts in open state
direction Symbol :bottom Which edge the drawer slides from (:bottom, :top, :left, :right)

Slots

Slot Description
with_trigger The element that opens the drawer (usually a button)
with_body The drawer content container (yields DrawerContentComponent)

DrawerContentComponent Slots

Slot Description
with_header Header section (yields with_title and with_description slots)
with_title Drawer title text (via header)
with_description Drawer description text (via header)
with_footer Footer section (usually contains action buttons)

Note: Mobile gesture support (swipe to close) is planned for a future release.

Stimulus Controller

This component requires JavaScript. The Stimulus controller shadcn--drawer provides interactivity.

Manages drawer open/close state, portal rendering, keyboard navigation, and animations.

Installation

Add to your config/importmap.rb:

pin "shadcn-rails", to: "shadcn/index.js"

Then in your app/javascript/controllers/index.js:

import { Application } from "@hotwired/stimulus"
import { registerShadcnControllers } from "shadcn-rails"

const application = Application.start()
registerShadcnControllers(application)

Or import just this controller:

import DrawerController from "shadcn-rails/controllers/drawer_controller"

application.register("shadcn--drawer", DrawerController)

Targets

Name Description
trigger The element that triggers the drawer to open
template Template containing the drawer content (for portal rendering)
overlay The backdrop overlay element
content The drawer content container

Values

Name Type Default Description
open Boolean false Current open/closed state
direction String bottom Which edge the drawer slides from

Actions

Action Description
open Opens the drawer
close Closes the drawer
toggle Toggles the drawer open/closed state

TypeScript

Type definitions are included. Import types as needed:

import type { DrawerController } from "shadcn-rails"

Accessibility

  • Uses role="dialog" for proper screen reader announcement
  • Sets aria-modal="true" to indicate modal behavior
  • Focuses the drawer content when opened
  • Pressing Escape closes the drawer
  • Prevents body scroll when drawer is open
  • Handle bar is shown for bottom/top drawers to indicate draggable behavior (visual only)
  • Clicking the overlay backdrop closes the drawer