How to Implement Expand/Collapse Feature in React

Irakli Tchigladze Feb 02, 2024
  1. Implement an Expand/Collapse Feature in React
  2. Expand/Collapse the Entire Container in React
  3. Expand/Collapse Specific Posts in React
  4. Expand or Collapse All Posts in React
  5. Conclusion
How to Implement Expand/Collapse Feature in React

When building web applications, you often need to dynamically change the appearance of a specific element(s) in DOM.

Other times, you need to display content only when the user wants to see it. This can help you manage large volumes of content without overwhelming the user and provide a good user experience.

In this article, we want to show you how to implement expand/collapse feature to display or hide containers in response to the click of a button by the user.

Implement an Expand/Collapse Feature in React

React allows you to hide and show components conditionally. Whether a component renders or not will depend on the value of the state variable, which can be changed in response to the user’s actions.

You can store a state variable of the boolean type. In JSX, you can use a ternary operator (or use an if condition within a function) to conditionally determine whether certain DOM elements (or components) should be rendered or not.

Let’s start by looking at an example: we have one parent component that displays a list of posts rendered by the <Post> component.

import "./styles.css";
import { useState } from "react";
export default function App() {
  let postsArr = ["post1", "post2", "post3", "post4", "post5"];
  const [postDisplay, setPostDisplay] = useState({
    post1: true,
    post2: true,
    post3: true,
    post4: true,
    post5: true
  });
  const [divDisplay, setDivDisplay] = useState(true);
  const handleClick = (post) => {
    const objectCopy = {
      ...postDisplay
    };
    objectCopy[post] = !objectCopy[post];
    setPostDisplay(objectCopy);
  };
  return (
    <div className="App">
      <button
        onClick={() =>
          setPostDisplay({
            post1: false,
            post2: false,
            post3: false,
            post4: false,
            post5: false
          })
        }
      >
        Hide All Posts
      </button>
      <br />
      <button
        onClick={() =>
          setPostDisplay({
            post1: true,
            post2: true,
            post3: true,
            post4: true,
            post5: true
          })
        }
      >
        Show All Posts
      </button>
      <br />
      <button onClick={() => setDivDisplay(!divDisplay)}>
        Expand/Collapse the post section
      </button>
      {postsArr.map((post) =>
        divDisplay ? (
          <div>
            <button onClick={() => handleClick(post)}>Expand {post}</button>
            {postDisplay[post] ? <Post key={post}></Post> : null}
          </div>
        ) : null
      )}
    </div>
  );
}

function Post() {
  return (
    <div className="post">
      <p>
        Some content
      </p>
    </div>
  );
}

In this case, instead of having one boolean state variable, we have an object of boolean values, one for each post. This allows us to expand only some posts and keep others collapsed (hidden).

Before we briefly break down this code, you can check the dynamic expand/collapse functionality on CodeSandbox.

Within our App component, we have an array of posts. In JSX, we apply a .map() method to the postsArr array and conditionally check if we should display the entire container of posts or individual posts.

let postsArr = ["post1", "post2", "post3", "post4", "post5"];
...
{postsArr.map((post) =>
        divDisplay ? (
          <div>
            <button onClick={() => handleClick(post)}>Expand {post}</button>
            {postDisplay[post] ? <Post key={post}></Post> : null}
          </div>
        ) : null
)}

Expand/Collapse the Entire Container in React

First, we check the value of divDisplay to determine whether we should render the <div> element that contains <Post /> components. If you visit the CodeSandbox live demo, you’ll see that we have a button.

Clicking this button will flip the current value of the divDisplay state variable. If the <div> container is collapsed, clicking this button will expand it.

If it’s expanded, clicking the button will hide the container. Let’s look at the code for this button.

<button onClick={() => setDivDisplay(!divDisplay)}>
        Expand/Collapse the post section
</button>

We set an onClick attribute on the <button> element and set its value to a simple arrow function which will make a call to the setDivDisplay() function, which updates the divDisplay state variable. We defined the updater function using the useState hook.

const [divDisplay, setDivDisplay] = useState(true);

We default set the value of the divDisplay variable to true. Later, users can flip the value of this variable by clicking the button.

Expand/Collapse Specific Posts in React

Assuming that we expand the entire <div> element that contains posts, we can also expand or collapse individual posts, which hide or show the post’s content.

Let’s look at the code section where we generate <Post> components.

{postsArr.map((post) =>
        divDisplay ? (
          <div>
            <button onClick={() => handleClick(post)}>Expand {post}</button>
            {postDisplay[post] ? <Post key={post}></Post> : null}
          </div>
        ) : null
)}

We apply a map() method on the postsArr array and return a <div> element that stores a button to show/hide button and a ternary operator that checks the value of the postDisplay object for the property of each item in the array.

It may be confusing, but let’s look at the array and state variables again.

let postsArr = ["post1", "post2", "post3", "post4", "post5"];

const [postDisplay, setPostDisplay] = useState({
    post1: true,
    post2: true,
    post3: true,
    post4: true,
    post5: true
  });

As you may know, the map() method will take each string in the array. Then it will check the value of this property in the postDisplay object.

For example, first map() method will take the 'post1' string, and render a <Post> component by checking the value of the postDisplay['post1'] expression.

{postDisplay[post] ? <Post key={post}></Post> : null}

Note that the map() method takes the callback function as its argument and treats each array item as a variable. Therefore we need to use the bracket notation to look up the property’s value.

The ternary operator returns null if the property value is false, which renders nothing.

Go to the CodeSandbox demo and try to expand and collapse individual posts by clicking a button. Using the object format allows us to expand the content of some posts while keeping others collapsed.

Expand or Collapse All Posts in React

At the top of the page, we have two buttons - the first collapses all posts which may be currently expanded, and the second expands all posts. Try clicking these buttons on the live demo to better understand their functionality.

Now let’s look at how this is accomplished within React.

<button
	onClick={() =>
	  setPostDisplay({
		post1: false,
		post2: false,
		post3: false,
		post4: false,
		post5: false
	  })
	}
  >
	Hide All Posts
  </button>
  <br />
  <button
	onClick={() =>
	  setPostDisplay({
		post1: true,
		post2: true,
		post3: true,
		post4: true,
		post5: true
	  })
	}
  >
	Show All Posts
  </button>

We set the onClick attribute, so whenever the user clicks on the first button, we call the setPostDisplay() function with an object where values of all properties (corresponding to the status of individual posts) are set to false.

The second button does the same, but all object properties are set to true in this case. Therefore, clicking these buttons will expand the content of all posts.

Conclusion

This is a very simple example; usually, websites have more stylish buttons to expand and collapse containers in React. Button styles may differ, but the functional implementation will be the same or very similar to what we showed here.

Irakli Tchigladze avatar Irakli Tchigladze avatar

Irakli is a writer who loves computers and helping people solve their technical problems. He lives in Georgia and enjoys spending time with animals.

LinkedIn