1

How can I create a collapsible/expandable div based on a button click? I'm trying to recreate something like the example plot in the AG Grid docs.

Here's my codepen and current problems:

  1. There is a transition when I collapse the div, but not when I expand it. There should be a transition when expanded or collapsed.

  2. When I collapse the div, the input elements still show on the page. Anything in the right div shouldn't show on the page when collapsed.

  3. When I set top: 50%, the button isn't centered. The button should be perfectly centered vertically.

  4. When I set left: 100% for the button, it appears in the right div instead of appearing at the end of the left div. It should appear at the end of the left div and never appear in the right div.

Any help or links to documentation that would help is greatly appreciated.

Simon1
  • 445
  • 4
  • 12

1 Answers1

2

In your JSX, I've changed the active class name to the left div. And using it to "push" the right panel when it's expanded instead of hiding the right panel, so we can get the transition working when toggling it.

import React, { useState } from 'react';
import './App.css';

function App() {
  const [isActive, setIsActive] = useState(true);

  return (
    <>
      <div className="container">
        <div className={isActive ? 'left' : 'left-expanded'}>
          <button className="handle" onClick={() => setIsActive(!isActive)}>
            Open
          </button>
        </div>
        <div className="right">
          <input type="text" />
          <br />
          <input type="text" />
        </div>
      </div>
    </>
  );
}

export default App;

And in your CSS, we now use min-width on the left div so it grows and shrinks in response to the active state. With overflow: hidden set on the container div, the right panel will be invisible when the left div is fully expanded. See the comments in the following CSS code for more explanation.

* {
  margin: 0;
  padding: 0;
  box-sizing: border-box;
}

body {
  padding: 2rem;
}

.container {
  height: 100px;
  display: flex;

  /* Ensure the right div is complete invisible when left div is expanded */
  overflow: hidden;
}

.left {
  height: 100%;

  /* Use this to push the right div */
  min-width: 70%;
  background-color: red;

  /* We only want the transition to take effect for the `min-width` property */
  transition: min-width 0.5s ease-in-out;
}

.left-expanded {
  height: 100%;
  min-width: 100%;
  background-color: red;
  transition: min-width 0.5s ease-in-out;
}

.right {
  height: 100%;
  min-width: 30%;
  background-color: blue;
}

.right input {
  width: 100%;
}

.handle {
  position: relative;
  top: 50%;

  /* Center the handle with translate, see this great answer on SO: https://stackoverflow.com/a/16801578/1727948 */
  transform-origin: left;
  transform: translate(50%, 50%) rotate(270deg);

  /* Ensure the handle stay in the left div, you can tweak the `-30px` to your desired position */
  left: calc(100% - 30px);
}

Here is a working codepen

Joshua
  • 3,055
  • 3
  • 22
  • 37