Sam
Sam

Reputation: 1230

Transition Flexbox As It Stretches With Additional Items

I would like to have a flexbox (the container, not the items) animate/transition as it stretches and shrinks to accommodate the different number of items appearing within it. Is there a way to make this possible? I can only find solutions for animating size of items within, not the flexbox itself.

Please see the snippet of scenario below:

const { useState } = React

const App = () => {
  const [showSecondDiv, setShowSecondDiv] = useState(true);
  
  return (
    <div>
      <button onClick={() => setShowSecondDiv(!showSecondDiv)}>{(showSecondDiv? "Shrink" : "Expand") + " flexbox"}</button>
      <div className="flex-container">
        <div>Hello</div>
        {showSecondDiv ? <div>World</div> : null}
      </div>
    </div>
  )
}

ReactDOM.render(<App />,
document.getElementById("root"))
.flex-container {
  border-style: solid;
  display: flex;
  flex-direction: column;
  transition: grow 2s;
  max-width: 100px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/17.0.1/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/17.0.1/umd/react-dom.production.min.js"></script>

<div id="root">
  <!-- This element's contents will be replaced with your component. -->
</div>

Upvotes: 0

Views: 2366

Answers (1)

SamiElk
SamiElk

Reputation: 2372

In your case you won't be able to transition your Flexbox

The auto value is often a very complex case. The specification recommends not animating from and to auto.

From what I understand this also apply to other values that are not fixed.

https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Transitions/Using_CSS_transitions#javascript_examples

You can see that there is no transition property that will apply the behavior you're seeking by applying `transition:all 2s'

However here is my attempt at producing the behavior I think you want by animating the max-height of the children element.

const { useState } = React;

const App = () => {
    const [showSecondDiv, setShowSecondDiv] = useState(true);
    const className = showSecondDiv ? 'grow' : 'shrink';
    return (
        <div>
            <button onClick={() => setShowSecondDiv(!showSecondDiv)}>
                {(showSecondDiv ? 'Shrink' : 'Expand') + ' flexbox'}
            </button>
            <div className="flex-container">
                <div>Hello</div>
                <div className={className}>World</div>
            </div>
        </div>
    );
};

ReactDOM.render(<App />, document.getElementById('root'));
.flex-container {
    border-style: solid;
    display: block;
    flex-direction: column;
    max-width: 100px;
}
.grow {
    animation-name: grow;
}
.shrink {
    animation-name: shrink;
}
.flex-container > div {
    overflow: hidden;
    animation-duration: 2s;
    animation-fill-mode: forwards;
}
@keyframes grow {
    from {
        max-height: 0px;
    }
    to {
        max-height: 1rem;
    }
}
@keyframes shrink {
    from {
        max-height: 1rem;
    }
    to {
        max-height: 0px;
    }
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/17.0.1/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/17.0.1/umd/react-dom.production.min.js"></script>

<div id="root">
  <!-- This element's contents will be replaced with your component. -->
</div>

Upvotes: 1

Related Questions