florian norbert bepunkt
florian norbert bepunkt

Reputation: 2539

React Material Tabs indicator not showing on first load

I have a simple Tabs setup with React Material UI (https://material-ui.com/components/tabs/) where the path value is set dynamically

export const Subnav: React.FC<Props> = ({ routes = [] }) => {
  const { pathname } = useLocation();
  const { push } = useHistory();    
  const handleChange = (e: ChangeEvent<{}>, path: string) => push(path);

  return (
    <Tabs
      indicatorColor="primary"
      onChange={handleChange}
      scrollButtons="auto"
      textColor="primary"
      value={pathname}
      variant="scrollable"
    >
      {routes.map(r => (
        <Tab label={r.name} value={r.path} />
      ))}
    </Tabs>
  );
};

When I first load a page / navigate to one of the tab routes, the correct tab is selected, but the indicator is not shown. In order for the indicator to be shown I have to click the same tab again or select another.

Upvotes: 9

Views: 6223

Answers (4)

Yuriy Sidorov
Yuriy Sidorov

Reputation: 101

export const Subnav: React.FC<Props> = ({ routes = [], render }) => {
  const { pathname } = useLocation();
  const { push } = useHistory();    
  const handleChange = (e: ChangeEvent<{}>, path: string) => push(path);

  const ref = useRef();

  useEffect(() => {ref.current.updateIndicator()}, [pathname, render])

  return (
    <Tabs
      action={ref}
      indicatorColor="primary"
      onChange={handleChange}
      scrollButtons="auto"
      textColor="primary"
      value={pathname}
      variant="scrollable"
    >
      {routes.map(r => (
        <Tab label={r.name} value={r.path} />
      ))}
    </Tabs>
  );
};

Put into props.render your anything dynamically value

Upvotes: 0

Kas Elvirov
Kas Elvirov

Reputation: 7980

My solution based on above ones but a bit different. The difference is that I update the indicator via a deferred call (setTimeout) with 400ms delay. Don't know real reason.

Below my definition of Mui-Tabs wrapper

import * as React from 'react';

import MaterialTabs, { TabsActions } from '@material-ui/core/Tabs';

import { withStyles } from '@material-ui/core';

import { IProps } from './types';

import styles from './styles';

class Tabs extends React.PureComponent<IProps> {
    tabsActions: React.RefObject<TabsActions>;

    constructor(props) {
        super(props);

        this.tabsActions = React.createRef();
    }

    /**
     * Read more about this here
     * - https://github.com/mui-org/material-ui/issues/9337#issuecomment-413789329
    */
    componentDidMount(): void {
        setTimeout(() => {
            if (this.tabsActions.current) {
                this.tabsActions.current.updateIndicator();
            }
        }, 400); // started working only with this timing
    }

    render(): JSX.Element {
        return (
            <MaterialTabs
                action={this.tabsActions}
                indicatorColor="primary"
                variant="scrollable"
                scrollButtons="auto"

                {...this.props}
            />
        );
    }
}

export default withStyles(styles)(Tabs);

Upvotes: -1

Hemantkumar Gaikwad
Hemantkumar Gaikwad

Reputation: 721

For this, there is one more way to handle this. In React material UI there is component <Grow/> you can warp <Tabs/> within <Grow/> and <Grow/> will correct the indicator position. Following is the example:

<Grow in={true}>
  <Tabs
   action={ref => ref.updateIndicator()}
  >
   <Tab label="Item One" />
    <Tab label="Item Two" />
    <Tab label="Item Three" />
  <Tabs>
</Grow>

Upvotes: 7

florian norbert bepunkt
florian norbert bepunkt

Reputation: 2539

This was resolved via https://github.com/mui-org/material-ui/issues/20527

You need to manually trigger the updateIndicator method. Easiest way to do this, is to call a resize event (which triggers the method)

useEffect(() => {
    window.dispatchEvent(new CustomEvent("resize"));
  }, []);

Alternatively add a ref to the actions prop and call the method directly. Still seems like a non-ideal solution, but it is what the maintainer provided.

Upvotes: 5

Related Questions