mui / material-ui

Material UI: Comprehensive React component library that implements Google's Material Design. Free forever.
https://mui.com/material-ui/
MIT License
93.82k stars 32.26k forks source link

[Tabs] indicator is animated from index 0 to the selected index on mount #9875

Closed xaviergonz closed 6 years ago

xaviergonz commented 6 years ago

When a tab control is first mounted there is an animation of the indicator to the first selected index.

Expected Behavior

The tab indicator should not animate to the first tab index, it should already be there.

Current Behavior

The tab indicator is animated until it reach the first selected index.

Your Environment

Tech Version
Material-UI latest beta
React 16
browser chrome 63
etc TS 2.6.2
oliviertassinari commented 6 years ago

Do you have a reproduction example?

xaviergonz commented 6 years ago

https://codesandbox.io/s/r1wo5xxj9m

Apparently the reposition bug was fixed :O , but it still animates to the first index on mount, so I changed the bug report accordingly

oliviertassinari commented 6 years ago

The issue is coming from the growing animation. There is two potential fix in userland. You can disable the animation or wait for the growing animation to complete before displaying the Tab. In-library land, maybe we can extend the server side logic to support this use case. I mean, we can wait for an index change event to switch the indicator positioning logic.

oliviertassinari commented 6 years ago

@xaviergonz The best workaround is to disable the indicator until the popover is fully open:

import React from 'react';
import ReactDOM from 'react-dom';
import Button from 'material-ui/Button';
import Popover from 'material-ui/Popover';
import Tabs, { Tab } from 'material-ui/Tabs';
import ShoppingBasket from 'material-ui-icons/ShoppingBasket';

class Buggy extends React.Component {
  state = {
    anchorEl: null,
    entered: false,
  };

  handleClickButton = () => {
    this.setState({
      anchorEl: ReactDOM.findDOMNode(this.button),
    });
  };

  handleClose = () => {
    this.setState({
      anchorEl: null,
      entered: false,
    });
  };

  handleEntered = () => {
    this.setState({
      entered: true,
    })
  };

  button = null;

  render() {
    const { anchorEl, entered } = this.state;

    return (
      <div>
        <Button
          ref={node => {
            this.button = node;
          }}
          onClick={this.handleClickButton}
        >
          Open Popover
        </Button>
        <Popover
          open={Boolean(anchorEl)}
          anchorEl={anchorEl}
          onClose={this.handleClose}
          onEntered={this.handleEntered}
        >
          <Tabs value={entered ? 3 : false} scrollable>
            <Tab icon={<ShoppingBasket />} />
            <Tab icon={<ShoppingBasket />} />
            <Tab icon={<ShoppingBasket />} />
            <Tab icon={<ShoppingBasket />} />
            <Tab icon={<ShoppingBasket />} />
          </Tabs>
        </Popover>
      </div>
    );
  }
}

export default Buggy;

https://codesandbox.io/s/r1wo5xxj9m

oronevron commented 5 years ago

I’m also dealing with the same issue (In my case, there is a Tabs component which renders within a Grow component). I've tried the suggested workaround but it's not solve the problem. A reproduction example: https://codesandbox.io/s/pjynxyvx0x

Any suggestions?

zhouzi commented 2 years ago

I just ran into this issue and created a minimal reproduction: https://codesandbox.io/s/basictabs-demo-material-ui-forked-wj5rmx?file=/demo.tsx

https://user-images.githubusercontent.com/2291025/170839676-054f1cbc-ca13-4fe6-b3f4-f96c7deb43e1.mp4

In this recording we can see that when the popover opens, the indicator briefly appears in a wrong position. The solution suggested in https://github.com/mui/material-ui/issues/9875#issuecomment-359169328 doesn't work well with custom indicator styles. Setting the value to false sets the indicator position to 0, 0 but doesn't hide it. An alternative is to set the indicator to visibility: hidden; and then to visibility: visible; when the popover's animation exited. But there's another issue, <Tabs /> calls updateIndicator with a debounce. So the style should not be removed immediately when the animation is over but with a slight delay.

It's still not perfect though as the indicator appears with a delay so from a user perspective it looks like the interface is laggy.

UPDATE: here is a solution for custom indicators: https://codesandbox.io/s/tender-dan-eg85bp?file=/src/App.tsx In this example I am setting the background color to transparent initially so there's a transition after the delayed update. Still not perfect but hopefully does the trick for some people.

In our case we ended up not using the indicator at all and instead apply the styles to the selected element directly. So we don't have the indicator moving from an item to another but at least there's no delay.

Zhaniarttt commented 2 years ago

There is two potential fix in userland. You can disable the animation or wait for the growing animation to complete before displaying the Tab.

did u find a solution for this ?