App Shell

A settings-style app shell using the inset sidebar — detached card main area with icon-collapsible nav.

Profile

Profile

How you appear to others on Acme.

Brief description for your profile. Max 160 chars.

Plan

Current: Pro

Hobby

$0

/mo

1 project

Community support

Pro

$19

/mo

Current

Unlimited projects

Priority email

Team

$49

/mo

Everything in Pro

SSO + SAML

Usage this month

Seats

4 / 10

API calls

18,240

Storage

6.3 GB

Bandwidth

142 GB

Delete workspace

This can't be undone. All projects, members, and data will be permanently deleted.

block_example do
  <div class="border rounded-xl overflow-hidden h-[1180px] relative [transform:translateZ(0)]">
    sui.sidebar_wrapper class: "!h-full" do
      sui.sidebar variant: :inset, collapsible: :icon do
        sui.sidebar_header do
          <div class="flex items-center gap-2 px-2 group-data-[collapsible=icon]:px-0 group-data-[collapsible=icon]:justify-center">
            <div class="flex h-8 w-8 shrink-0 items-center justify-center rounded-md bg-primary text-primary-foreground text-sm font-bold">A</div>
            <div class="min-w-0 group-data-[collapsible=icon]:hidden">
              <p class="truncate text-sm font-semibold">Acme Inc</p>
              <p class="truncate text-xs text-muted-foreground">Enterprise</p>
            </div>
          </div>
        end

        sui.sidebar_content do
          sui.sidebar_group do
            sui.sidebar_group_label "General"
            sui.sidebar_group_content do
              sui.sidebar_menu do
                [["Profile", :user, true], ["Account", :settings, false], ["Notifications", :"circle-alert", false], ["Billing", :"credit-card", false]].each do |(label, ic, active)|
                  sui.sidebar_menu_item do
                    sui.sidebar_menu_button label, "#", active: active, tooltip: label do
                      sui.icon(ic)
                      <span>label</span>
                    end
                  end
                end
              end
            end
          end

          sui.sidebar_separator

          sui.sidebar_group do
            sui.sidebar_group_label "Team"
            sui.sidebar_group_content do
              sui.sidebar_menu do
                [["Members", :users, "12"], ["Invitations", :mail, "3"], ["Roles", :shield, nil]].each do |(label, ic, badge)|
                  sui.sidebar_menu_item do
                    sui.sidebar_menu_button label, "#", tooltip: label do
                      sui.icon(ic)
                      <span>label</span>
                    end
                    sui.sidebar_menu_badge badge if badge
                  end
                end
              end
            end
          end
        end

        sui.sidebar_footer do
          <div class="flex items-center gap-2 px-2 py-1.5 group-data-[collapsible=icon]:px-0 group-data-[collapsible=icon]:justify-center">
            sui.avatar(class: "h-8 w-8 shrink-0") { sui.avatar_fallback "JD" }
            <div class="min-w-0 group-data-[collapsible=icon]:hidden">
              <p class="truncate text-sm font-medium">Jane Doe</p>
              <p class="truncate text-xs text-muted-foreground">jane@acme.com</p>
            </div>
          </div>
        end
      end

      sui.sidebar_inset do
        sui.sidebar_inset_header do
          sui.sidebar_trigger
          sui.separator class: "mx-2 h-4", orientation: :vertical
          <span class="text-sm font-medium">Profile</span>
          sui.layout.row gap: 2, class: "ml-auto" do
            sui.button "Invite", variant: :outline, size: :sm
            sui.button "Upgrade", size: :sm
          end
        end

        sui.sidebar_inset_content class: "overflow-visible" do
          sui.layout.stack gap: 8, class: "p-8" do
            sui.layout.row gap: 4, justify: :between, align: :start do
              sui.layout.stack gap: 1 do
                sui.h2 "Profile"
                sui.muted { "How you appear to others on Acme." }
              end
              sui.layout.row gap: 2 do
                sui.button "Cancel", variant: :ghost, size: :sm
                sui.button "Save changes", size: :sm
              end
            end

            sui.layout.grid cols: 1, gap: 6, class: "md:grid-cols-2" do
              sui.layout.stack gap: 2 do
                sui.label "Display name", for: "display-name"
                sui.input id: "display-name", value: "Jane Doe"
              end
              sui.layout.stack gap: 2 do
                sui.label "Email", for: "email"
                sui.input id: "email", type: "email", value: "[email protected]"
              end
              sui.layout.stack gap: 2, class: "md:col-span-2" do
                sui.label "Bio", for: "bio"
                sui.input id: "bio", value: "Principal engineer, into weird compilers."
                sui.muted { "Brief description for your profile. Max 160 chars." }
              end
            end

            sui.layout.stack gap: 4 do
              sui.layout.row justify: :between do
                sui.h3 "Plan"
                sui.badge "Current: Pro", variant: :secondary
              end

              sui.layout.grid cols: 1, gap: 4, class: "md:grid-cols-3" do
                [
                  {name: "Hobby", price: "$0",  current: false, feats: ["1 project", "Community support"]},
                  {name: "Pro",   price: "$19", current: true,  feats: ["Unlimited projects", "Priority email"]},
                  {name: "Team",  price: "$49", current: false, feats: ["Everything in Pro", "SSO + SAML"]}
                ].each do |plan|
                  sui.card(class: "p-5 #{plan[:current] ? 'ring-2 ring-primary' : ''}") do
                    sui.layout.stack gap: 4 do
                      sui.layout.row justify: :between, align: :start do
                        sui.layout.stack gap: 1 do
                          sui.p plan[:name], class: "font-semibold !my-0"
                          sui.layout.row gap: 1, align: :baseline do
                            sui.p plan[:price], class: "text-2xl font-bold !my-0"
                            sui.muted { "/mo" }
                          end
                        end
                        sui.badge "Current" if plan[:current]
                      end

                      sui.layout.stack gap: 2 do
                        plan[:feats].each do |f|
                          sui.layout.row gap: 2 do
                            sui.icon(:check, class: "size-4 text-primary")
                            sui.p f, class: "text-sm !my-0"
                          end
                        end
                      end

                      sui.button (plan[:current] ? "Manage" : "Switch"), variant: (plan[:current] ? :outline : :default), class: "w-full"
                    end
                  end
                end
              end
            end

            sui.layout.stack gap: 4 do
              sui.h3 "Usage this month"
              sui.layout.grid cols: 2, gap: 4, class: "md:grid-cols-4" do
                [["Seats", "4 / 10"], ["API calls", "18,240"], ["Storage", "6.3 GB"], ["Bandwidth", "142 GB"]].each do |(label, value)|
                  sui.card(class: "p-4") do
                    sui.layout.stack gap: 1 do
                      sui.muted { label }
                      sui.p value, class: "text-xl font-semibold !my-0"
                    end
                  end
                end
              end
            end

            sui.card(class: "p-6 border-destructive/40") do
              sui.layout.row gap: 4, justify: :between, align: :start do
                sui.layout.stack gap: 1 do
                  sui.p "Delete workspace", class: "font-semibold !my-0"
                  sui.muted { "This can't be undone. All projects, members, and data will be permanently deleted." }
                end
                sui.button "Delete…", variant: :destructive, size: :sm
              end
            end
          end
        end
      end
    end

What this demonstrates

  • sidebar_wrapper + sidebar variant: :inset → detached rounded main card.
  • collapsible: :icon → click the trigger in the header to collapse nav to an icon rail.
  • sidebar_menu_badge on Members / Invitations; active state on Profile via active:.
  • sidebar_inset_header is sticky; sidebar_inset_content scrolls beneath it.
  • Body content uses sui.layout primitives — no raw flex divs.