Blocks

Sidebar

A composable, collapsible navigation panel wired to a Stimulus controller. Build app shells with a persistent left (or right) drawer that collapses off-canvas.

Installation

bin/rails g shadcnrb:component sidebar

Note

Because this docs page is itself rendered inside a sidebar layout, embedding a full sidebar_wrapper in the preview would create a nested layout conflict. Instead, the individual building blocks are shown below. For a full working demo, see the live sidebar test.

Usage — individual pieces

Child parts are reached via the proxy yielded by sui.sidebar_wrapper do |s|. For isolated demos outside a wrapper, sui.sidebar_proxy returns the same proxy without rendering the shell. menu_button mirrors Rails link_to — pass a name + path and the active state is auto-detected via current_page?.

<!-- default -->
<%= s.menu_button "Dashboard", "#" %>
<!-- active: true -->
<%= s.menu_button "Active item", "#", active: true %>
<!-- icon: :home -->
<%= s.menu_button "Home", "#", icon: :home %>

For anything beyond a plain link — button_to with method: :delete, Turbo options, nested icons — pass a block. The wrapper renders a styled <div role="button"> and your Rails helper fills the row.

Platform

<!-- menu_button (block form with button_to) -->
<div class="w-64 bg-sidebar rounded-md p-2">
  <%= s.menu_button do %>
    <%= button_to "Sign out", "#", method: :delete %>
  <% end %>
</div>
<!-- group_label -->
<div class="w-48 bg-sidebar rounded-md">
  <%= s.group_label "Platform" %>
</div>
<!-- separator -->
<div class="w-48 bg-sidebar rounded-md py-2">
  <%= s.separator %>
</div>

Full structure (code only)

Assemble these methods to build a complete sidebar shell. The sidebar_wrapper owns the Stimulus controller; s.trigger and s.rail both dispatch the toggle action.

sui.sidebar_wrapper do |s|
  s.sidebar do
    s.header do
      tag.span "My App", class: "font-semibold text-sm px-2"
    end
    s.content do
      s.group do
        s.group_label "Platform"
        s.group_content do
          s.menu do
            s.menu_item do
              s.menu_button "Dashboard", root_path
            end
            s.menu_item do
              s.menu_button "Settings", settings_path
            end
          end
        end
      end
      s.separator
      s.group do
        s.group_label "Account"
        s.group_content do
          s.menu do
            s.menu_item do
              s.menu_button "Profile", profile_path
            end
          end
        end
      end
    end
    s.footer do
      tag.span "Footer content"
    end
    s.rail
  end
  s.inset do
    tag.header(class: "flex items-center gap-2 p-4") do
      s.trigger
    end
    tag.div(class: "p-4") do
      tag.p "Main content area"
    end
  end
end

API

methodsignaturedescription
sui.sidebar_wrapper(**opts, &block)Outermost div. Mounts the Stimulus sidebar controller and sets CSS custom properties for width. Yields a proxy s.
sui.sidebar_proxyReturns a bare proxy for rendering individual pieces outside a wrapper (e.g. docs previews).
s.sidebar(side:, variant:, collapsible:, **opts, &block)The sidebar panel itself. side: is :left (default) or :right.
s.header(**opts, &block)Flex column at the top of the sidebar, typically for a logo or app name.
s.content(**opts, &block)Scrollable flex column that fills the remaining vertical space.
s.group(**opts, &block)A labelled section inside sidebar content, padded on all sides.
s.group_label(name = nil, **opts, &block)Small muted heading above a group of links.
s.group_content(**opts, &block)Wrapper div for the group's menu list.
s.menu(**opts, &block)Unordered list (ul) that holds menu items with gap spacing.
s.menu_item(**opts, &block)List item (li) wrapper for a single menu button.
s.menu_button(name, options, active: nil, **html_opts, &block)An anchor styled as a sidebar row. Mirrors link_to. Auto-sets active via current_page?; pass active: true/false to override.
s.separator(**opts)Horizontal rule styled with sidebar border colour, with side margins.
s.footer(**opts, &block)Flex column pinned to the bottom of the sidebar.
s.inset(**opts, &block)The main content area (main) that sits beside the sidebar, grows to fill remaining space.
s.trigger(**opts)Icon button that dispatches shadcnrb--sidebar--component#toggle on click to expand/collapse the sidebar.
s.rail(**opts)Narrow invisible hit-area along the sidebar edge — also toggles on click, visible as a faint line on hover.