Sheet
A panel that slides out from the edge of the screen. Extends the Dialog component to display content without covering the entire screen.
Installation
Add the component to your project:
rails generate shadcn:component sheet
Usage
<%= render Shadcn::SheetComponent.new(side: :right) do |sheet| %>
<% sheet.with_trigger do %>
<%= render Shadcn::ButtonComponent.new(variant: :outline) do %>Open Sheet<% end %>
<% end %>
<% sheet.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="grid gap-4 py-4">
<div class="grid grid-cols-4 items-center gap-4">
<%= render Shadcn::LabelComponent.new(for: "name", class_name: "text-right") { "Name" } %>
<%= render Shadcn::InputComponent.new(id: "name", value: "John Doe", class_name: "col-span-3") %>
</div>
<div class="grid grid-cols-4 items-center gap-4">
<%= render Shadcn::LabelComponent.new(for: "username", class_name: "text-right") { "Username" } %>
<%= render Shadcn::InputComponent.new(id: "username", value: "@johndoe", class_name: "col-span-3") %>
</div>
</div>
<% content.with_footer do %>
<%= render Shadcn::ButtonComponent.new(type: "submit") { "Save changes" } %>
<% end %>
<% end %>
<% end %>
Examples
Sides
Use the side property to specify which edge the sheet slides out from. Options: :top, :right, :bottom, :left.
Top
<%= render Shadcn::SheetComponent.new(side: :top) do |sheet| %>
<% sheet.with_trigger do %>
<%= render Shadcn::ButtonComponent.new(variant: :outline) do %>Top<% end %>
<% end %>
<% sheet.with_body do |content| %>
<% content.with_header do |header| %>
<% header.with_title { "Notifications" } %>
<% header.with_description { "View your recent notifications." } %>
<% end %>
<div class="py-4">
<p class="text-sm">No new notifications.</p>
</div>
<% end %>
<% end %>
Right (Default)
<%= render Shadcn::SheetComponent.new(side: :right) do |sheet| %>
<% sheet.with_trigger do %>
<%= render Shadcn::ButtonComponent.new(variant: :outline) do %>Right<% end %>
<% end %>
<% sheet.with_body do |content| %>
<% content.with_header do |header| %>
<% header.with_title { "Settings" } %>
<% header.with_description { "Configure your preferences." } %>
<% end %>
<div class="py-4">
<p class="text-sm">Settings panel content.</p>
</div>
<% end %>
<% end %>
Bottom
<%= render Shadcn::SheetComponent.new(side: :bottom) do |sheet| %>
<% sheet.with_trigger do %>
<%= render Shadcn::ButtonComponent.new(variant: :outline) do %>Bottom<% end %>
<% end %>
<% sheet.with_body do |content| %>
<% content.with_header do |header| %>
<% header.with_title { "Details" } %>
<% header.with_description { "Additional information." } %>
<% end %>
<div class="py-4">
<p class="text-sm">Details panel content.</p>
</div>
<% end %>
<% end %>
Left
<%= render Shadcn::SheetComponent.new(side: :left) do |sheet| %>
<% sheet.with_trigger do %>
<%= render Shadcn::ButtonComponent.new(variant: :outline) do %>Left<% end %>
<% end %>
<% sheet.with_body do |content| %>
<% content.with_header do |header| %>
<% header.with_title { "Navigation" } %>
<% header.with_description { "Browse sections." } %>
<% end %>
<div class="py-4">
<nav class="flex flex-col gap-2">
<a href="#" class="text-sm hover:underline">Home</a>
<a href="#" class="text-sm hover:underline">About</a>
<a href="#" class="text-sm hover:underline">Contact</a>
</nav>
</div>
<% end %>
<% end %>
With Form
Sheets are ideal for forms and multi-step workflows that don't need to completely interrupt the user.
<%= render Shadcn::SheetComponent.new(side: :right) do |sheet| %>
<% sheet.with_trigger do %>
<%= render Shadcn::ButtonComponent.new do %>Create Account<% end %>
<% end %>
<% sheet.with_body do |content| %>
<% content.with_header do |header| %>
<% header.with_title { "Create New Account" } %>
<% header.with_description { "Enter the details below to create a new account." } %>
<% end %>
<div class="grid gap-4 py-4">
<div class="space-y-2">
<%= render Shadcn::LabelComponent.new(for: "name") { "Full Name" } %>
<%= render Shadcn::InputComponent.new(id: "name", placeholder: "John Doe") %>
</div>
<div class="space-y-2">
<%= render Shadcn::LabelComponent.new(for: "email") { "Email" } %>
<%= render Shadcn::InputComponent.new(id: "email", type: "email", placeholder: "email@example.com") %>
</div>
<div class="space-y-2">
<%= render Shadcn::LabelComponent.new(for: "role") { "Role" } %>
<%= render Shadcn::InputComponent.new(id: "role", placeholder: "Developer") %>
</div>
</div>
<% content.with_footer do %>
<div class="flex gap-2">
<%= render Shadcn::ButtonComponent.new(variant: :outline, data: { action: "click->shadcn--sheet#close" }) { "Cancel" } %>
<%= render Shadcn::ButtonComponent.new(type: "submit") { "Create Account" } %>
</div>
<% end %>
<% end %>
<% end %>
API Reference
SheetComponent
API Reference
| Prop | Type | Default | Description |
|---|---|---|---|
| side |
Symbol
|
:right
|
Side the sheet appears from. Options: :top, :right, :bottom, :left |
| open |
Boolean
|
false
|
Whether the sheet starts in open state |
| class_name |
String
|
nil
|
Additional CSS classes to apply |
| data |
Hash
|
{}
|
Data attributes to add to the element |
Slots
| Slot | Description |
|---|---|
| with_trigger | The element that opens the sheet (usually a button) |
| with_body | The sheet content container (yields SheetContentComponent) |
SheetContentComponent Slots
| Slot | Description |
|---|---|
| with_header | Header section (yields with_title and with_description slots) |
| with_title | Sheet title text |
| with_description | Sheet description text |
| with_footer | Footer section (usually contains action buttons) |
Stimulus Controller
This component requires JavaScript. The Stimulus controller shadcn--sheet provides interactivity.
Manages sheet open/close state, focus trapping, keyboard navigation, and accessibility for slide-out panels.
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 SheetController from "shadcn-rails/controllers/sheet_controller"
application.register("shadcn--sheet", SheetController)
Targets
| Name | Description |
|---|---|
| trigger | The element that triggers the sheet to open |
| template | Template containing the sheet content (for portal rendering) |
| overlay | The backdrop overlay element |
| content | The sheet panel container |
Values
| Name | Type | Default | Description |
|---|---|---|---|
| open | Boolean |
false |
Current open/closed state |
| side | String |
right |
Which side the sheet appears from |
Actions
| Action | Description |
|---|---|
| open | Opens the sheet |
| close | Closes the sheet |
TypeScript
Type definitions are included. Import types as needed:
import type { SheetController } from "shadcn-rails"
Accessibility
- Uses
role="dialog"for proper screen reader announcement - Sets
aria-modal="true"to indicate modal behavior - Traps focus within the sheet when open
- Pressing Escape closes the sheet
- Returns focus to trigger element when closed
- Clicking the overlay closes the sheet
- Use
data-action="click->shadcn--sheet#close"on any element to close the sheet programmatically
On This Page