Drawer
A slide-out panel that can appear from any edge of the screen. Perfect for mobile-optimized navigation, forms, and detail views.
Edit Profile
Make changes to your profile here. Click save when you're done.
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
Are you sure?
This action cannot be undone.
<%= 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.
Edit Profile
Make changes to your profile here.
<%= 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.
Bottom Drawer
Content slides in from the bottom.
Drawer content here.
Top Drawer
Content slides in from the top.
Drawer content here.
Left Drawer
Content slides in from the left.
Drawer content here.
Right Drawer
Content slides in from the right.
Drawer content here.
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)
Install the package:
npm install shadcn-rails
Then in your app/javascript/controllers/index.js:
import { Application } from "@hotwired/stimulus"
import { registerShadcnControllers } from "shadcn-rails"
const application = Application.start()
registerShadcnControllers(application)
Install the package:
yarn add shadcn-rails
Then in your app/javascript/controllers/index.js:
import { Application } from "@hotwired/stimulus"
import { registerShadcnControllers } from "shadcn-rails"
const application = Application.start()
registerShadcnControllers(application)
Install the package:
npm install shadcn-rails
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
On This Page