Collapsible
An interactive component which expands and collapses a panel.
<%= render Shadcn::Collapsible.new(class_name: "w-full max-w-md space-y-2") do |collapsible| %>
<% collapsible.with_trigger(variant: :outline, class_name: "w-full justify-between") do %>
<span>@peduarte starred 3 repositories</span>
<svg xmlns="http://www.w3.org/2000/svg" class="h-4 w-4 shrink-0 transition-transform duration-200 group-data-[state=open]:rotate-180" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">
<path d="m6 9 6 6 6-6"></path>
</svg>
<% end %>
<% collapsible.with_body do %>
<div class="rounded-md border px-4 py-3 text-sm">
@radix-ui/primitives
</div>
<% end %>
<% end %>
Installation
Add the component to your project:
rails generate shadcn:add collapsible
Usage
<div class="w-full max-w-md space-y-2">
<%= render Shadcn::Collapsible.new do |collapsible| %>
<% collapsible.with_trigger(variant: :outline) do %>
Toggle
<% end %>
<% collapsible.with_body do %>
<div class="rounded-md border px-4 py-3 text-sm">
This is the collapsible content. Click the button above to toggle visibility.
</div>
<% end %>
<% end %>
</div>
Examples
Basic
A simple collapsible with a trigger button and content area.
<div class="w-full max-w-md space-y-2">
<%= render Shadcn::Collapsible.new do |collapsible| %>
<% collapsible.with_trigger(variant: :outline) do %>
Toggle
<% end %>
<% collapsible.with_body do %>
<div class="rounded-md border px-4 py-3 text-sm">
This is the collapsible content. Click the button above to toggle visibility.
</div>
<% end %>
<% end %>
</div>
Initially Open
Set open: true to start with content expanded.
open parameter is set to true.
<div class="w-full max-w-md space-y-2">
<%= render Shadcn::Collapsible.new(open: true) do |collapsible| %>
<% collapsible.with_trigger(variant: :outline, class_name: "w-full justify-between") do %>
<span>Toggle Details</span>
<svg xmlns="http://www.w3.org/2000/svg" class="h-4 w-4 shrink-0 transition-transform duration-200 group-data-[state=open]:rotate-180" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">
<path d="m6 9 6 6 6-6"></path>
</svg>
<% end %>
<% collapsible.with_body do %>
<div class="rounded-md border px-4 py-3 text-sm">
This content is visible by default because the <code class="rounded bg-muted px-1 py-0.5 font-mono text-sm">open</code> parameter is set to <code class="rounded bg-muted px-1 py-0.5 font-mono text-sm">true</code>.
</div>
<% end %>
<% end %>
</div>
Disabled
Prevent toggling by setting disabled: true.
<div class="w-full max-w-md space-y-2">
<%= render Shadcn::Collapsible.new(disabled: true) do |collapsible| %>
<% collapsible.with_trigger(variant: :outline, class_name: "w-full justify-between") do %>
<span>Disabled Collapsible</span>
<svg xmlns="http://www.w3.org/2000/svg" class="h-4 w-4 shrink-0 transition-transform duration-200 group-data-[state=open]:rotate-180" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">
<path d="m6 9 6 6 6-6"></path>
</svg>
<% end %>
<% collapsible.with_body do %>
<div class="rounded-md border px-4 py-3 text-sm">
This content cannot be toggled because the collapsible is disabled.
</div>
<% end %>
<% end %>
</div>
With Smooth Animation
The collapsible includes smooth height animations by default, powered by the Stimulus controller.
The animation automatically adjusts to the content height.
This creates a smooth, natural expand/collapse effect.
The 200ms transition provides responsive feedback without feeling sluggish.
<div class="w-full max-w-md space-y-2">
<%= render Shadcn::Collapsible.new do |collapsible| %>
<% collapsible.with_trigger(variant: :outline) do %>
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="mr-2" aria-hidden="true">
<path d="M8 3H5a2 2 0 0 0-2 2v3"></path>
<path d="M21 8V5a2 2 0 0 0-2-2h-3"></path>
<path d="M3 16v3a2 2 0 0 0 2 2h3"></path>
<path d="M16 21h3a2 2 0 0 0 2-2v-3"></path>
</svg>
Show Details
<% end %>
<% collapsible.with_body do %>
<div class="rounded-md border px-4 py-3 text-sm space-y-2">
<p>The animation automatically adjusts to the content height.</p>
<p>This creates a smooth, natural expand/collapse effect.</p>
<p>The 200ms transition provides responsive feedback without feeling sluggish.</p>
</div>
<% end %>
<% end %>
</div>
Settings Panel
A practical example showing a collapsible settings panel.
Account Settings
Manage your account preferences
<%= render Shadcn::Card.new(class_name: "w-full max-w-md") do |card| %>
<% card.with_header do |header| %>
<% header.with_title { "Account Settings" } %>
<% header.with_description { "Manage your account preferences" } %>
<% end %>
<% card.with_content do %>
<div class="space-y-4">
<%= render Shadcn::Collapsible.new do |collapsible| %>
<% collapsible.with_trigger(
variant: nil,
size: nil,
class_name: "group flex w-full items-center justify-between rounded-md p-2 text-left transition-colors hover:bg-muted focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring"
) do %>
<span class="space-y-0.5">
<span class="block text-sm font-medium">Notification Preferences</span>
<span class="block text-sm text-muted-foreground">Configure how you receive notifications</span>
</span>
<svg xmlns="http://www.w3.org/2000/svg" class="h-4 w-4 shrink-0 transition-transform duration-200 group-data-[state=open]:rotate-180" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">
<path d="m6 9 6 6 6-6"></path>
</svg>
<% end %>
<% collapsible.with_body do %>
<div class="pt-4 space-y-3">
<div class="flex items-center justify-between">
<span class="text-sm">Email notifications</span>
<%= render Shadcn::Checkbox.new(id: "email-notif") %>
</div>
<div class="flex items-center justify-between">
<span class="text-sm">Push notifications</span>
<%= render Shadcn::Checkbox.new(id: "push-notif") %>
</div>
<div class="flex items-center justify-between">
<span class="text-sm">SMS notifications</span>
<%= render Shadcn::Checkbox.new(id: "sms-notif") %>
</div>
</div>
<% end %>
<% end %>
</div>
<% end %>
<% end %>
Nested Content
Collapsible works with complex nested content and other components.
<div class="w-full max-w-md space-y-2">
<%= render Shadcn::Collapsible.new do |collapsible| %>
<% collapsible.with_trigger(variant: :ghost, size: :sm, class_name: "w-full justify-between") do %>
<span class="text-sm font-semibold">Project Files</span>
<svg xmlns="http://www.w3.org/2000/svg" class="h-4 w-4 shrink-0 transition-transform duration-200 group-data-[state=open]:rotate-180" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">
<path d="m6 9 6 6 6-6"></path>
</svg>
<% end %>
<% collapsible.with_body do %>
<div class="rounded-md border divide-y">
<div class="px-4 py-3 text-sm flex items-center justify-between">
<span class="font-mono">src/components/</span>
<%= render Shadcn::Badge.new(variant: :secondary) { "Directory" } %>
</div>
<div class="px-4 py-3 text-sm flex items-center justify-between">
<span class="font-mono">README.md</span>
<%= render Shadcn::Badge.new(variant: :outline) { "File" } %>
</div>
<div class="px-4 py-3 text-sm flex items-center justify-between">
<span class="font-mono">package.json</span>
<%= render Shadcn::Badge.new(variant: :outline) { "File" } %>
</div>
</div>
<% end %>
<% end %>
</div>
API Reference
Collapsible
Collapsible Props
| Prop | Type | Default | Description |
|---|---|---|---|
| open |
Boolean
|
false
|
Whether the collapsible starts in the expanded state |
| disabled |
Boolean
|
false
|
When true, prevents toggling the collapsible state |
| class_name |
String
|
nil
|
Additional CSS classes to apply to the container |
CollapsibleTrigger
CollapsibleTrigger Props
| Prop | Type | Default | Description |
|---|---|---|---|
| variant |
Symbol, nil
|
:ghost
|
Button style variant from Shadcn::Button, or nil for custom styling |
| size |
Symbol, nil
|
:sm
|
Button size from Shadcn::Button, or nil for custom sizing |
| class_name |
String
|
nil
|
Additional CSS classes to apply to the trigger button |
Slots
| Slot | Description |
|---|---|
| with_trigger | Renders the button that toggles the collapsible. Pass trigger options such as variant:, size:, and class_name:. |
| with_body | The collapsible content that is shown or hidden when toggled. |
Stimulus Controller
This component requires JavaScript. The Stimulus controller shadcn--collapsible provides interactivity.
Manages the collapsible state and handles smooth expand/collapse animations with automatic height calculation.
Installation
Add to your config/importmap.rb:
pin "shadcn", to: "index.esm.js"
Then in your app/javascript/controllers/index.js:
import { Application } from "@hotwired/stimulus"
import { registerShadcnControllers } from "shadcn"
const application = Application.start()
registerShadcnControllers(application)
Install the package:
npm install shadcn-rails-stimulus
Then in your app/javascript/controllers/index.js:
import { Application } from "@hotwired/stimulus"
import { registerShadcnControllers } from "shadcn-rails-stimulus"
const application = Application.start()
registerShadcnControllers(application)
Install the package:
yarn add shadcn-rails-stimulus
Then in your app/javascript/controllers/index.js:
import { Application } from "@hotwired/stimulus"
import { registerShadcnControllers } from "shadcn-rails-stimulus"
const application = Application.start()
registerShadcnControllers(application)
Install the package:
npm install shadcn-rails-stimulus
Then in your app/javascript/controllers/index.js:
import { Application } from "@hotwired/stimulus"
import { registerShadcnControllers } from "shadcn-rails-stimulus"
const application = Application.start()
registerShadcnControllers(application)
Or import just this controller:
import CollapsibleController from "shadcn-rails-stimulus/controllers/collapsible_controller"
application.register("shadcn--collapsible", CollapsibleController)
Targets
| Name | Description |
|---|---|
| trigger | The button that toggles the state |
| content | The content area that expands/collapses |
Values
| Name | Type | Default | Description |
|---|---|---|---|
| open | Boolean |
false
|
Current open/closed state of the collapsible |
| disabled | Boolean |
false
|
Whether the collapsible is disabled |
Actions
| Action | Description |
|---|---|
| toggle | Toggles between open and closed states (respects disabled) |
| open | Opens the collapsible (respects disabled) |
| close | Closes the collapsible |
TypeScript
Type definitions are included. Import types as needed:
import type { CollapsibleController } from "shadcn-rails-stimulus"
Accessibility
- The trigger renders as a semantic
button. - The trigger includes
aria-expandedand keeps it synchronized as the collapsible opens and closes. - Trigger and content use
data-stateattributes to track open and closed states. - Content is hidden with the
hiddenattribute when collapsed. - Disabled state prevents interaction and renders a disabled trigger button.
Best Practices:
- Use concise, descriptive trigger labels.
- Provide visual indicators (icons, arrows) that show the current state
- Ensure sufficient color contrast for all states
On This Page