Resizable

Accessible resizable panel groups and layouts with keyboard support.

Requires JavaScript
One
Two

Installation

Add the component to your project:

rails generate shadcn:component resizable

Usage

<%= render Shadcn::ResizablePanelGroupComponent.new(direction: :horizontal) do |group| %>
  <% group.with_panel(default_size: 50) do %>
    <div class="flex h-full items-center justify-center p-6">
      <span class="font-semibold">One</span>
    </div>
  <% end %>
  <% group.with_handle(with_handle: true) %>
  <% group.with_panel(default_size: 50) do %>
    <div class="flex h-full items-center justify-center p-6">
      <span class="font-semibold">Two</span>
    </div>
  <% end %>
<% end %>

Examples

Vertical

Use the direction: :vertical option for vertical resizing.

Header
Content
<%= render Shadcn::ResizablePanelGroupComponent.new(direction: :vertical, class_name: "h-[200px]") do |group| %>
  <% group.with_panel(default_size: 25) do %>
    <div class="flex h-full items-center justify-center p-6">
      <span class="font-semibold">Header</span>
    </div>
  <% end %>
  <% group.with_handle %>
  <% group.with_panel(default_size: 75) do %>
    <div class="flex h-full items-center justify-center p-6">
      <span class="font-semibold">Content</span>
    </div>
  <% end %>
<% end %>

With Handle

Add a visible grip handle with with_handle: true.

Sidebar
Content
<%= render Shadcn::ResizablePanelGroupComponent.new(direction: :horizontal) do |group| %>
  <% group.with_panel(default_size: 30) do %>
    <div class="flex h-full items-center justify-center p-6">
      <span class="font-semibold">Sidebar</span>
    </div>
  <% end %>
  <% group.with_handle(with_handle: true) %>
  <% group.with_panel(default_size: 70) do %>
    <div class="flex h-full items-center justify-center p-6">
      <span class="font-semibold">Content</span>
    </div>
  <% end %>
<% end %>

Three Panels

Create layouts with multiple panels by adding more panels and handles.

One
Two
Three
<%= render Shadcn::ResizablePanelGroupComponent.new(direction: :horizontal) do |group| %>
  <% group.with_panel(default_size: 25) do %>
    <div class="flex h-full items-center justify-center p-6">
      <span class="font-semibold">One</span>
    </div>
  <% end %>
  <% group.with_handle(with_handle: true) %>
  <% group.with_panel(default_size: 50) do %>
    <div class="flex h-full items-center justify-center p-6">
      <span class="font-semibold">Two</span>
    </div>
  <% end %>
  <% group.with_handle(with_handle: true) %>
  <% group.with_panel(default_size: 25) do %>
    <div class="flex h-full items-center justify-center p-6">
      <span class="font-semibold">Three</span>
    </div>
  <% end %>
<% end %>

Min/Max Constraints

Use min_size and max_size to constrain panel sizes.

20-40%
60-80%
<%= render Shadcn::ResizablePanelGroupComponent.new(direction: :horizontal) do |group| %>
  <% group.with_panel(default_size: 30, min_size: 20, max_size: 40) do %>
    <div class="flex h-full items-center justify-center p-6">
      <span class="font-semibold">20-40%</span>
    </div>
  <% end %>
  <% group.with_handle(with_handle: true) %>
  <% group.with_panel(default_size: 70, min_size: 60, max_size: 80) do %>
    <div class="flex h-full items-center justify-center p-6">
      <span class="font-semibold">60-80%</span>
    </div>
  <% end %>
<% end %>

Nested Layout

Create complex layouts by nesting panel groups.

Sidebar
Header
Content
<%= render Shadcn::ResizablePanelGroupComponent.new(direction: :horizontal, class_name: "h-[300px]") do |group| %>
  <% group.with_panel(default_size: 25) do %>
    <div class="flex h-full items-center justify-center p-6">
      <span class="font-semibold">Sidebar</span>
    </div>
  <% end %>
  <% group.with_handle %>
  <% group.with_panel(default_size: 75) do %>
    <%= render Shadcn::ResizablePanelGroupComponent.new(direction: :vertical) do |inner| %>
      <% inner.with_panel(default_size: 30) do %>
        <div class="flex h-full items-center justify-center p-6">
          <span class="font-semibold">Header</span>
        </div>
      <% end %>
      <% inner.with_handle %>
      <% inner.with_panel(default_size: 70) do %>
        <div class="flex h-full items-center justify-center p-6">
          <span class="font-semibold">Content</span>
        </div>
      <% end %>
    <% end %>
  <% end %>
<% end %>

Persistent Layout

Use auto_save_id to persist panel sizes in localStorage.

Persistent
Layout

Resize the panels above, then refresh the page. Your layout will be restored.

<%= render Shadcn::ResizablePanelGroupComponent.new(
  direction: :horizontal,
  auto_save_id: "my-layout"
) do |group| %>
  <% group.with_panel(default_size: 50) do %>
    <div class="flex h-full items-center justify-center p-6">
      <span class="font-semibold">Panel One</span>
    </div>
  <% end %>
  <% group.with_handle(with_handle: true) %>
  <% group.with_panel(default_size: 50) do %>
    <div class="flex h-full items-center justify-center p-6">
      <span class="font-semibold">Panel Two</span>
    </div>
  <% end %>
<% end %>

API Reference

ResizablePanelGroupComponent

API Reference

Prop Type Default Description
direction Symbol :horizontal Direction of panels (:horizontal or :vertical)
auto_save_id String nil ID for persisting sizes to localStorage

Slots

Slot Props Description
with_panel default_size:, min_size:, max_size: Resizable panel with optional size constraints (percentages 0-100)
with_handle with_handle: Draggable separator between panels

Stimulus Controller

This component requires JavaScript. The Stimulus controller shadcn--resizable provides interactivity.

Handles panel resizing with mouse, touch, and keyboard support.

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)

Or import just this controller:

import ResizableController from "shadcn-rails/controllers/resizable_controller"

application.register("shadcn--resizable", ResizableController)

Targets

Name Description
panel Resizable panel elements
handle Draggable resize handles

Values

Name Type Default Description
direction String "horizontal" Panel direction (horizontal or vertical)
autoSaveId String null ID for localStorage persistence

Actions

Action Description
startResize Begin resize operation (mouse/touch)

TypeScript

Type definitions are included. Import types as needed:

import type { ResizableController } from "shadcn-rails"

Accessibility

  • Handle uses role="separator" for semantics
  • Sets appropriate aria-orientation
  • Handle is keyboard focusable with tabindex="0"
  • Keyboard navigation:
    • Arrow Left/Arrow Right to resize horizontal panels
    • Arrow Up/Arrow Down to resize vertical panels
    • Shift + Arrow for larger adjustments (10%)
    • Home to collapse previous panel to minimum
    • End to collapse next panel to minimum
  • Touch support for mobile devices