Drawer
A slide-in panel anchored to any edge of the viewport — supports right, left, top, and bottom sides with animated open/close transitions.
Installation
bin/rails g shadcnrb:component drawer
Usage
Wrap everything in sui.drawer do |drawer|. Child parts (drawer.trigger, drawer.content, …) live on the proxy.
Drawer
Side panel content goes here.
Body content.
<%= sui.drawer do |drawer| %> <%= drawer.trigger "Open drawer", variant: :outline %> <%= drawer.content do %> <%= drawer.header do %> <%= drawer.title "Drawer" %> <%= drawer.description "Side panel content goes here." %> <% end %> <div class="p-4 text-sm">Body content.</div> <% end %> <% end %>
Sides
Pass side: to drawer.content — one of :right (default), :left, :top, :bottom.
Right drawer
Slides in from the right.
Content panel.
Left drawer
Slides in from the left.
Content panel.
Top drawer
Slides down from the top.
Content panel.
Bottom drawer
Slides up from the bottom.
Content panel.
<div class="flex flex-wrap gap-2"> <%= sui.drawer do |drawer| %> <%= drawer.trigger "Right (default)", variant: :outline %> <%= drawer.content do %> <%= drawer.header do %> <%= drawer.title "Right drawer" %> <%= drawer.description "Slides in from the right." %> <% end %> <div class="p-4 text-sm">Content panel.</div> <% end %> <% end %> <%= sui.drawer do |drawer| %> <%= drawer.trigger "Left", variant: :outline %> <%= drawer.content side: :left do %> <%= drawer.header do %> <%= drawer.title "Left drawer" %> <%= drawer.description "Slides in from the left." %> <% end %> <div class="p-4 text-sm">Content panel.</div> <% end %> <% end %> <%= sui.drawer do |drawer| %> <%= drawer.trigger "Top", variant: :outline %> <%= drawer.content side: :top do %> <%= drawer.header do %> <%= drawer.title "Top drawer" %> <%= drawer.description "Slides down from the top." %> <% end %> <div class="p-4 text-sm">Content panel.</div> <% end %> <% end %> <%= sui.drawer do |drawer| %> <%= drawer.trigger "Bottom", variant: :outline %> <%= drawer.content side: :bottom do %> <%= drawer.header do %> <%= drawer.title "Bottom drawer" %> <%= drawer.description "Slides up from the bottom." %> <% end %> <div class="p-4 text-sm">Content panel.</div> <% end %> <% end %> </div>
Settings drawer
A practical example with a header, scrollable body, and sticky footer.
Settings
Manage your account preferences.
<%= sui.drawer do |drawer| %> <%= drawer.trigger "Settings", variant: :outline %> <%= drawer.content do %> <%= drawer.header do %> <%= drawer.title "Settings" %> <%= drawer.description "Manage your account preferences." %> <% end %> <div class="flex-1 overflow-y-auto p-4 space-y-4"> <div class="flex items-center justify-between"> <%= sui.label "Dark mode" %> <%= sui.switch name: "dark_mode" %> </div> <div class="flex items-center justify-between"> <%= sui.label "Notifications" %> <%= sui.switch name: "notifications", checked: true %> </div> </div> <%= drawer.footer do %> <%= sui.button "Save changes" %> <% end %> <% end %> <% end %>
API
| Method | Args | Default | Description |
|---|---|---|---|
sui.drawer | **opts | — | Root container; mounts the Stimulus controller and yields a drawer proxy |
drawer.trigger | name, variant:, size: | :default, :md | Button that opens the drawer panel on click |
drawer.content | side: | :right | Backdrop + anchored panel; side: is :right :left :top :bottom |
drawer.header | **opts | — | Padded flex column for title and description |
drawer.footer | **opts | — | Sticky bottom area with padding for action buttons |
drawer.title | name | nil | Semibold heading rendered as h2 |
drawer.description | name | nil | Muted supporting text rendered as p |