DEV Community

Patrick Moore
Patrick Moore

Posted on

Building Collapsible Content with react-collapse in React

react-collapse is a lightweight library for creating smooth, animated collapsible content in React applications. It provides a simple API for expanding and collapsing content with CSS transitions, making it easy to create accordions, expandable sections, and collapsible panels. This guide walks through setting up and creating collapsible content using react-collapse with React, from installation to a working implementation.

demo animation

Prerequisites

Before you begin, make sure you have:

  • Node.js version 14.0 or higher installed
  • npm, yarn, or pnpm package manager
  • A React project (version 16.8 or higher) or create-react-app setup
  • Basic knowledge of React hooks (useState)
  • Familiarity with JavaScript/TypeScript
  • Understanding of CSS transitions

Installation

Install react-collapse using your preferred package manager:

npm install react-collapse
Enter fullscreen mode Exit fullscreen mode

Or with yarn:

yarn add react-collapse
Enter fullscreen mode Exit fullscreen mode

Or with pnpm:

pnpm add react-collapse
Enter fullscreen mode Exit fullscreen mode

After installation, your package.json should include:

{
  "dependencies": {
    "react-collapse": "^5.1.0",
    "react": "^18.0.0",
    "react-dom": "^18.0.0"
  }
}
Enter fullscreen mode Exit fullscreen mode

Project Setup

react-collapse requires minimal setup. Import the component and you're ready to use it.

First Example / Basic Usage

Let's create a simple collapsible section. Create a new file src/CollapseExample.jsx:

// src/CollapseExample.jsx
import React, { useState } from 'react';
import { Collapse } from 'react-collapse';

function CollapseExample() {
  const [isOpen, setIsOpen] = useState(false);

  return (
    <div style={{ padding: '20px', maxWidth: '600px', margin: '0 auto' }}>
      <h2>Basic Collapse Example</h2>
      <button
        onClick={() => setIsOpen(!isOpen)}
        style={{
          padding: '10px 20px',
          backgroundColor: '#007bff',
          color: 'white',
          border: 'none',
          borderRadius: '4px',
          cursor: 'pointer',
          marginBottom: '10px'
        }}
      >
        {isOpen ? 'Collapse' : 'Expand'}
      </button>
      <Collapse isOpened={isOpen}>
        <div style={{
          padding: '20px',
          backgroundColor: '#f8f9fa',
          border: '1px solid #ddd',
          borderRadius: '4px'
        }}>
          <p>This is collapsible content. It smoothly expands and collapses when you click the button.</p>
          <p>You can put any content here - text, images, forms, or other components.</p>
        </div>
      </Collapse>
    </div>
  );
}

export default CollapseExample;
Enter fullscreen mode Exit fullscreen mode

Update your App.jsx:

// src/App.jsx
import React from 'react';
import CollapseExample from './CollapseExample';
import './App.css';

function App() {
  return (
    <div className="App">
      <CollapseExample />
    </div>
  );
}

export default App;
Enter fullscreen mode Exit fullscreen mode

This creates a basic collapsible section with smooth animations.

Understanding the Basics

react-collapse provides a simple component:

  • Collapse component: Main collapsible container
  • isOpened prop: Controls whether content is expanded or collapsed
  • Smooth animations: CSS-based transitions
  • Flexible content: Can contain any React content
  • Customizable: Configurable transition timing

Key concepts:

  • State management: Use useState to control isOpened state
  • Toggle function: Create a function to toggle the state
  • Content wrapping: Wrap content in Collapse component
  • Animations: Transitions are handled automatically
  • Styling: Style the content as needed

Here's an example with multiple collapsible sections:

// src/AdvancedCollapseExample.jsx
import React, { useState } from 'react';
import { Collapse } from 'react-collapse';

function AdvancedCollapseExample() {
  const [openSections, setOpenSections] = useState({});

  const toggleSection = (id) => {
    setOpenSections(prev => ({
      ...prev,
      [id]: !prev[id]
    }));
  };

  const sections = [
    { id: 1, title: 'Section 1', content: 'Content for section 1' },
    { id: 2, title: 'Section 2', content: 'Content for section 2' },
    { id: 3, title: 'Section 3', content: 'Content for section 3' }
  ];

  return (
    <div style={{ padding: '20px', maxWidth: '600px', margin: '0 auto' }}>
      <h2>Advanced Collapse Example</h2>
      {sections.map(section => (
        <div key={section.id} style={{ marginBottom: '10px' }}>
          <button
            onClick={() => toggleSection(section.id)}
            style={{
              width: '100%',
              padding: '10px 20px',
              backgroundColor: openSections[section.id] ? '#28a745' : '#007bff',
              color: 'white',
              border: 'none',
              borderRadius: '4px',
              cursor: 'pointer',
              textAlign: 'left'
            }}
          >
            {section.title} {openSections[section.id] ? '' : ''}
          </button>
          <Collapse isOpened={openSections[section.id]}>
            <div style={{
              padding: '15px',
              backgroundColor: '#f8f9fa',
              border: '1px solid #ddd',
              borderTop: 'none',
              borderRadius: '0 0 4px 4px'
            }}>
              <p>{section.content}</p>
            </div>
          </Collapse>
        </div>
      ))}
    </div>
  );
}

export default AdvancedCollapseExample;
Enter fullscreen mode Exit fullscreen mode

Practical Example / Building Something Real

Let's build a comprehensive FAQ component with collapsible answers:

// src/FAQComponent.jsx
import React, { useState } from 'react';
import { Collapse } from 'react-collapse';

function FAQComponent() {
  const [openItems, setOpenItems] = useState({});

  const toggleItem = (id) => {
    setOpenItems(prev => ({
      ...prev,
      [id]: !prev[id]
    }));
  };

  const faqItems = [
    {
      id: 1,
      question: 'How do I install react-collapse?',
      answer: 'You can install react-collapse using npm, yarn, or pnpm. Run: npm install react-collapse'
    },
    {
      id: 2,
      question: 'Is react-collapse accessible?',
      answer: 'react-collapse provides smooth animations but you may need to add ARIA attributes for full accessibility.'
    },
    {
      id: 3,
      question: 'Can I customize the animation?',
      answer: 'Yes, you can customize the animation timing and easing through CSS or by using the theme prop.'
    },
    {
      id: 4,
      question: 'Does it work with server-side rendering?',
      answer: 'Yes, react-collapse works with SSR. Make sure to handle the initial render state properly.'
    },
    {
      id: 5,
      question: 'Can I have multiple sections open at once?',
      answer: 'Yes, you can control multiple Collapse components independently using separate state variables.'
    }
  ];

  return (
    <div style={{ padding: '20px', maxWidth: '800px', margin: '0 auto' }}>
      <h1>Frequently Asked Questions</h1>
      <div style={{ marginTop: '20px' }}>
        {faqItems.map(item => (
          <div key={item.id} style={{ marginBottom: '15px', border: '1px solid #ddd', borderRadius: '8px', overflow: 'hidden' }}>
            <button
              onClick={() => toggleItem(item.id)}
              style={{
                width: '100%',
                padding: '15px 20px',
                backgroundColor: openItems[item.id] ? '#007bff' : '#f8f9fa',
                color: openItems[item.id] ? 'white' : '#333',
                border: 'none',
                cursor: 'pointer',
                textAlign: 'left',
                fontSize: '16px',
                fontWeight: '500',
                display: 'flex',
                justifyContent: 'space-between',
                alignItems: 'center',
                transition: 'background-color 0.3s'
              }}
            >
              <span>{item.question}</span>
              <span style={{ fontSize: '20px' }}>
                {openItems[item.id] ? '' : '+'}
              </span>
            </button>
            <Collapse isOpened={openItems[item.id]}>
              <div style={{
                padding: '20px',
                backgroundColor: 'white',
                borderTop: '1px solid #ddd'
              }}>
                <p style={{ margin: 0, lineHeight: '1.6' }}>{item.answer}</p>
              </div>
            </Collapse>
          </div>
        ))}
      </div>
    </div>
  );
}

export default FAQComponent;
Enter fullscreen mode Exit fullscreen mode

Now create a settings panel with collapsible sections:

// src/SettingsPanel.jsx
import React, { useState } from 'react';
import { Collapse } from 'react-collapse';

function SettingsPanel() {
  const [openSections, setOpenSections] = useState({
    general: false,
    privacy: false,
    notifications: false
  });

  const toggleSection = (section) => {
    setOpenSections(prev => ({
      ...prev,
      [section]: !prev[section]
    }));
  };

  return (
    <div style={{ padding: '20px', maxWidth: '600px', margin: '0 auto' }}>
      <h2>Settings</h2>
      <div style={{ marginTop: '20px' }}>
        {/* General Settings */}
        <div style={{ marginBottom: '15px', border: '1px solid #ddd', borderRadius: '8px', overflow: 'hidden' }}>
          <button
            onClick={() => toggleSection('general')}
            style={{
              width: '100%',
              padding: '15px 20px',
              backgroundColor: openSections.general ? '#007bff' : '#f8f9fa',
              color: openSections.general ? 'white' : '#333',
              border: 'none',
              cursor: 'pointer',
              textAlign: 'left',
              fontSize: '16px',
              fontWeight: '500'
            }}
          >
            General Settings {openSections.general ? '' : ''}
          </button>
          <Collapse isOpened={openSections.general}>
            <div style={{ padding: '20px', backgroundColor: 'white' }}>
              <label style={{ display: 'block', marginBottom: '10px' }}>
                <input type="checkbox" style={{ marginRight: '8px' }} />
                Enable dark mode
              </label>
              <label style={{ display: 'block', marginBottom: '10px' }}>
                <input type="checkbox" style={{ marginRight: '8px' }} />
                Show notifications
              </label>
            </div>
          </Collapse>
        </div>

        {/* Privacy Settings */}
        <div style={{ marginBottom: '15px', border: '1px solid #ddd', borderRadius: '8px', overflow: 'hidden' }}>
          <button
            onClick={() => toggleSection('privacy')}
            style={{
              width: '100%',
              padding: '15px 20px',
              backgroundColor: openSections.privacy ? '#007bff' : '#f8f9fa',
              color: openSections.privacy ? 'white' : '#333',
              border: 'none',
              cursor: 'pointer',
              textAlign: 'left',
              fontSize: '16px',
              fontWeight: '500'
            }}
          >
            Privacy Settings {openSections.privacy ? '' : ''}
          </button>
          <Collapse isOpened={openSections.privacy}>
            <div style={{ padding: '20px', backgroundColor: 'white' }}>
              <label style={{ display: 'block', marginBottom: '10px' }}>
                <input type="checkbox" style={{ marginRight: '8px' }} />
                Share analytics data
              </label>
              <label style={{ display: 'block', marginBottom: '10px' }}>
                <input type="checkbox" style={{ marginRight: '8px' }} />
                Allow cookies
              </label>
            </div>
          </Collapse>
        </div>

        {/* Notification Settings */}
        <div style={{ marginBottom: '15px', border: '1px solid #ddd', borderRadius: '8px', overflow: 'hidden' }}>
          <button
            onClick={() => toggleSection('notifications')}
            style={{
              width: '100%',
              padding: '15px 20px',
              backgroundColor: openSections.notifications ? '#007bff' : '#f8f9fa',
              color: openSections.notifications ? 'white' : '#333',
              border: 'none',
              cursor: 'pointer',
              textAlign: 'left',
              fontSize: '16px',
              fontWeight: '500'
            }}
          >
            Notification Settings {openSections.notifications ? '' : ''}
          </button>
          <Collapse isOpened={openSections.notifications}>
            <div style={{ padding: '20px', backgroundColor: 'white' }}>
              <label style={{ display: 'block', marginBottom: '10px' }}>
                <input type="checkbox" style={{ marginRight: '8px' }} />
                Email notifications
              </label>
              <label style={{ display: 'block', marginBottom: '10px' }}>
                <input type="checkbox" style={{ marginRight: '8px' }} />
                Push notifications
              </label>
            </div>
          </Collapse>
        </div>
      </div>
    </div>
  );
}

export default SettingsPanel;
Enter fullscreen mode Exit fullscreen mode

Update your App.jsx:

// src/App.jsx
import React from 'react';
import FAQComponent from './FAQComponent';
import SettingsPanel from './SettingsPanel';
import './App.css';

function App() {
  return (
    <div className="App">
      <FAQComponent />
      <SettingsPanel />
    </div>
  );
}

export default App;
Enter fullscreen mode Exit fullscreen mode

This example demonstrates:

  • FAQ component with collapsible answers
  • Settings panel with multiple sections
  • Independent state management
  • Custom styling
  • Smooth animations

Common Issues / Troubleshooting

  1. Content not collapsing: Make sure the isOpened prop is properly controlled by state. The component needs a boolean value to work correctly.

  2. Animation not smooth: The library uses CSS transitions. If animations aren't smooth, check for CSS conflicts or ensure the component has proper dimensions.

  3. Multiple sections not working: Use separate state variables or an object to manage multiple collapse states independently.

  4. Content jumping: This can happen if the content height changes. Ensure the content has a stable structure or use fixed heights if needed.

  5. Styling issues: The Collapse component wraps your content in a div. Make sure your styles account for this wrapper element.

  6. Initial state: If you want a section to be open by default, set the initial state to true in your useState hook.

Next Steps

Now that you have an understanding of react-collapse:

  • Learn about advanced collapse configurations
  • Explore custom animation timing
  • Implement accordion behavior
  • Add accessibility features
  • Create nested collapsible sections
  • Learn about other collapse libraries
  • Check the official repository: https://github.com/nkbt/react-collapse

Summary

You've successfully set up react-collapse in your React application and created FAQ components and settings panels with smooth collapsible animations. react-collapse provides a simple, lightweight solution for creating expandable content sections.

SEO Keywords

react-collapse
React collapsible content
react-collapse tutorial
React expand collapse
react-collapse installation
React accordion component
react-collapse example
React collapse animation
react-collapse setup
React collapsible section
react-collapse customization
React collapse library
react-collapse FAQ
React smooth collapse
react-collapse getting started

Top comments (0)