Collapsible Rails Components
Show and hide content sections with smooth animations. Perfect for expanding cards, showing additional details, or creating interactive content areas that users can toggle on demand.
Installation
1. Stimulus Controller Setup
Start by adding the following controller to your project:
import { Controller } from "@hotwired/stimulus";
export default class extends Controller {
static targets = ["content", "collapsedIcon", "expandedIcon"];
static values = { open: Boolean };
connect() {
// Set initial state based on data attribute
this.isOpen = this.openValue;
this.updateDisplay();
}
toggle() {
this.isOpen = !this.isOpen;
this.updateDisplay();
}
updateDisplay() {
const content = this.contentTarget;
const collapsedIcon = this.collapsedIconTarget;
const expandedIcon = this.expandedIconTarget;
if (this.isOpen) {
// Show content
content.style.maxHeight = content.scrollHeight + "px";
content.style.opacity = "1";
content.setAttribute("data-state", "open");
// Fade to expanded icon
collapsedIcon.style.opacity = "0";
expandedIcon.style.opacity = "1";
// Update container state
this.element.setAttribute("data-state", "open");
} else {
// Hide content
content.style.maxHeight = "0";
content.style.opacity = "0";
content.setAttribute("data-state", "closed");
// Fade to collapsed icon
collapsedIcon.style.opacity = "1";
expandedIcon.style.opacity = "0";
// Update container state
this.element.setAttribute("data-state", "closed");
}
}
}
Examples
Basic Collapsible
A simple collapsible component that shows/hides content with smooth animations. Features dual icons that automatically transition between collapsed and expanded states.
Rails developer starred 3 repositories
rails/rails
hotwired/stimulus
hotwired/turbo-rails
<div class="flex w-full justify-center">
<div data-controller="collapsible" data-collapsible-open-value="false" data-state="closed" class="w-[350px] space-y-2">
<!-- Header with toggle button -->
<div class="flex items-center justify-between space-x-4">
<h4 class="text-sm font-semibold">Rails developer starred 3 repositories</h4>
<button type="button" class="relative flex items-center justify-center gap-1.5 rounded-lg bg-transparent p-1.5 -sm font-medium whitespace-nowrap text-neutral-800 transition-all duration-100 ease-in-out select-none hover:bg-neutral-100 hover:text-neutral-900 focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-neutral-600 disabled:cursor-not-allowed disabled:opacity-50 dark:text-neutral-50 dark:hover:bg-neutral-600/50 dark:hover:text-white dark:focus-visible:outline-neutral-200" data-action="click->collapsible#toggle">
<!-- Collapsed state icon (visible by default) -->
<svg data-collapsible-target="collapsedIcon" xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 18 18" class="absolute transition-opacity duration-200 ease-in-out size-4.5" style="opacity: 0;">
<g fill="none" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5" stroke="currentColor">
<polyline points="12.5 6.25 9 2.75 5.5 6.25"></polyline>
<polyline points="12.5 11.75 9 15.25 5.5 11.75"></polyline>
</g>
</svg>
<!-- Expanded state icon (hidden by default) -->
<svg data-collapsible-target="expandedIcon" xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 18 18" class="transition-opacity duration-200 ease-in-out size-4.5" style="opacity: 0;">
<g fill="none" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5" stroke="currentColor">
<polyline points="5.5 3.5 9 7 12.5 3.5"></polyline>
<polyline points="5.5 14.5 9 11 12.5 14.5"></polyline>
</g>
</svg>
<span class="sr-only">Toggle</span>
</button>
</div>
<!-- Always visible content -->
<div class="rounded-md border border-neutral-200 bg-neutral-50 dark:border-neutral-700 dark:bg-neutral-700/50 px-4 py-3 font-mono text-sm">rails/rails</div>
<!-- Collapsible content -->
<div data-collapsible-target="content" data-state="closed" class="space-y-2 overflow-hidden transition-all duration-300 ease-in-out" style="max-height: 0; opacity: 0;">
<div class="rounded-md border border-neutral-200 bg-neutral-50 dark:border-neutral-700 dark:bg-neutral-700/50 px-4 py-3 font-mono text-sm">hotwired/stimulus</div>
<div class="rounded-md border border-neutral-200 bg-neutral-50 dark:border-neutral-700 dark:bg-neutral-700/50 px-4 py-3 font-mono text-sm">hotwired/turbo-rails</div>
</div>
</div>
</div>
Configuration
The collapsible component is powered by a Stimulus controller that provides smooth animations and flexible configuration options for creating interactive content sections.
Controller Setup
Basic collapsible structure with required data attributes:
<div data-controller="collapsible" data-collapsible-open-value="false">
<div class="flex items-center justify-between">
<h4>Content Title</h4>
<button data-action="click->collapsible#toggle">
<svg data-collapsible-target="collapsedIcon"><!-- Icon for collapsed state --></svg>
<svg data-collapsible-target="expandedIcon"><!-- Icon for expanded state --></svg>
</button>
</div>
<div data-collapsible-target="content" class="overflow-hidden transition-all duration-300">
<!-- Collapsible content goes here -->
</div>
</div>
Configuration Values
Value | Description | Type | Default |
---|---|---|---|
open
|
Controls the initial open/closed state when the component loads |
boolean
|
false
|
Targets
Target | Description | Required |
---|---|---|
content
|
The collapsible content area that shows/hides with smooth animations | Required |
collapsedIcon
|
Icon element displayed when content is collapsed | Optional |
expandedIcon
|
Icon element displayed when content is expanded | Optional |
Actions
Action | Description | Usage |
---|---|---|
toggle
|
Toggles the collapsible content between open and closed states |
click->collapsible#toggle
|
Animation Features
- Smooth Height Transitions: Content expands and collapses with smooth max-height animations
- Opacity Fading: Content fades in/out during transitions for polished visual effects
- Icon Switching: Automatic fade transitions between collapsed and expanded icon states
-
State Attributes: Automatic
data-state
attribute management for custom styling
Styling with CSS
The component automatically sets data-state
attributes that you can use for custom styling:
-
Container:
data-state="open"
ordata-state="closed"
-
Content:
data-state="open"
ordata-state="closed"
Usage Tips
-
CSS Transitions: Add
transition-all duration-300
to the content target for smooth animations -
Overflow Hidden: Use
overflow-hidden
on the content target to prevent content from showing during animations -
Icon Positioning: Use
position: absolute
on icon targets to overlay them for smooth transitions -
Initial State: Set the initial
data-collapsible-open-value
based on your design needs