Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I animate card height in Material-UI (React)

I'm new to React and Material UI, so please bear with me :P

What I want to do is, have a card that dynamically changes height as the content changes. According to the docs, this should happen automatically, and it does, but I want the height to animate to the new value.

So this is the relevant code:

var SomeAwesomeComponent = React.createClass({

getInitialState: function(){
  return {
      text: 'Test'
  }
},

componentDidMount: function(){
  var self = this;
setInterval(function(){
    self.setState({
        text: 'Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello '
    })
  },2000)
},

render: function() {
    var cardStyle = {
        transition: '1s'
    }
    return (
        <div>
            <Card>
                <CardText transitionEnabled={true} style={{cardStyle}}>
                    {this.state.text}
                </CardText>
            </Card>
        </div>
    );
}

});

What I can see is, the height changes, but it jumps to the new value. I want it to 'transition' to the new value. The docs say this can be done using 'transitionEnabled', but I can't seem to get it to work. Can anyone help?

Thanks

like image 768
siddhant Avatar asked Jul 01 '15 01:07

siddhant


2 Answers

So I found a solution that works.

It was more of a CSS issue than React/Material-UI.

You have to explicitly set the heights in both states of the card (and it cannot be 'auto'). What I did was, I saved the height as a state of the component, and updated it when I wanted it to expand (when I changed the text).

Here:

getInitialState: function(){
  return {
      text: 'Test',
      height: '10vh'
  }
},

componentDidMount: function(){
  var self = this;
setInterval(function(){
    self.setState({
        text: 'Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello ',
        height: '15vh'
    })
  },2000)
},

render: function() {
    var cardStyle = {
        display: 'block',
        width: '80vw',
        transitionDuration: '0.3s',
        height: this.state.height
    }
    return (
        <div>
            <Card style={cardStyle}>
                <CardText>
                    {this.state.text}
                </CardText>
            </Card>
        </div>
    );

I'm pretty sure this is not the best way to do this, so if anyone knows a better solution, do let me know.

Thanks :)

like image 67
siddhant Avatar answered Sep 19 '22 12:09

siddhant


I ran into this issue as well. My way is to add an onExpandChange event on the outer Card element, from the callback method you can set the visibility state on your expandable elements. Then you can do something like [https://stackoverflow.com/a/8331169/3246854] in Jake's answer to toggle and ease in/out the elements. Doing it this way allows you to set auto height on the expandable element.

The only drawback is the ease-out transition will appear to have a short delay since the transition is done on the max-height rather than the actual height. Its not a big deal as long as you adjust the ease-out speed accordingly.

I am using the version 0.14.4 as of the time I wrote this.

onExpandChange = (x) => {
  this.setState({showDetails: x})
}

render() {  
  var on_show_styles = {maxHeight: "2000px", transition: "max-height 1s ease-in"};
  var on_hide_styles = {maxHeight: "0", transition: "max-height 0.15s ease-out", overflow: "hidden"};
  
  return (
    <Card onExpandChange={this.onExpandChange}>
      <CardHeader
        title="I lost my rubber duck"
        subtitle="Click here to help me find it"
        actAsExpander={true}
        showExpandableButton={true}
      />
      <CardText style={this.state.showDetails ? on_show_styles : on_hide_styles}>
        <div>
          <p><b>Description:</b></p>
          <p>Here are the details about my rubber duck</p>
        </div>
      </CardText>
    </Card>
  )
}
like image 36
Sam Avatar answered Sep 19 '22 12:09

Sam