question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Tabs indicator custom width and position

See original GitHub issue
  • I have searched the issues of this repository and believe that this is not a duplicate.

Expected Behavior

I’d like the ability to transform the indicator style (namely width and left) within the Tabs component based on the default value. This would be in the form of an optional function prop that looks like this:

function transformIndicatorStyle({left, width}) {
    return {
        left: left + 6,
        width: width - 12,
    };
}

This function would be invoked either before setting the indicatorStyle state value, or before the style is passed to the TabIndicator child during render.

Current Behavior

The Tabs indicator is locked to the left and width of the currently selected tab’s getBoundingClientRect.

Steps to Reproduce (for bugs)

This sandbox demonstrates how far I’m able to go for indicator customization. I’ve modified the height and margins of the indicator using class overrides, but I’m not able to access or modify the width because it’s a function of the selected tab size. Notice the overhang on the right side of the selection.

https://codesandbox.io/s/6j663n24zw

Context

We are creating a component that wraps AppBar and Tabs. It has a segmented option which places the indicator underneath the tab (z-axis) at full height, similar to what was done for #10123, with some margin around the sides. Style overrides allow us to mostly accomplish what we want, but we’re unable to find a way to modify the indicator width so that it plays nicely with the margin.

segmented_tabs

Your Environment

Tech Version
Material-UI 1.0.0-beta.34
React 16.2.0
browser Chrome 64

Issue Analytics

  • State:closed
  • Created 6 years ago
  • Comments:18 (7 by maintainers)

github_iconTop GitHub Comments

11reactions
oliviertassinaricommented, Feb 14, 2019

@HiranmayaGundu Ok, can you add this example in the documentation? 😄 https://codesandbox.io/s/xl526z333q alongside this demo? https://material-ui.com/demos/tabs/#customized-tabs

import React from "react";
import PropTypes from "prop-types";
import { withStyles } from "@material-ui/core/styles";
import Tabs from "@material-ui/core/Tabs";
import Tab from "@material-ui/core/Tab";
import Typography from "@material-ui/core/Typography";

const styles = theme => ({
  root: {
    backgroundColor: "#2e1534"
  },
  typography: {
    padding: theme.spacing.unit * 3
  }
});

const StyledTabs = withStyles(theme => ({
  indicator: {
    display: "flex",
    justifyContent: "center",
    backgroundColor: "transparent",
    "& > div": {
      maxWidth: 40,
      width: "100%",
      backgroundColor: "#635ee7"
    }
  }
}))(props => <Tabs {...props} TabIndicatorProps={{ children: <div /> }} />);

const StyledTab = withStyles(theme => ({
  root: {
    textTransform: "initial",
    color: "#9e88a2",
    fontWeight: theme.typography.fontWeightLight,
    fontSize: theme.typography.pxToRem(15),
    marginRight: theme.spacing.unit * 1,
    "&:hover": {
      color: "#fff"
    },
    "&$selected": {
      color: "#fff"
    },
    "&:focus": {
      color: "#fff"
    }
  },
  selected: {}
}))(props => <Tab disableRipple {...props} />);

class CustomizedTabs extends React.Component {
  state = {
    value: 0
  };

  handleChange = (event, value) => {
    this.setState({ value });
  };

  render() {
    const { classes } = this.props;
    const { value } = this.state;

    return (
      <div className={classes.root}>
        <StyledTabs value={value} onChange={this.handleChange}>
          <StyledTab label="Workflows" />
          <StyledTab label="Datasets" />
          <StyledTab label="Connections" />
        </StyledTabs>
        <Typography className={classes.typography} />
      </div>
    );
  }
}

CustomizedTabs.propTypes = {
  classes: PropTypes.object.isRequired
};

export default withStyles(styles)(CustomizedTabs);

feb-14-2019 09-56-08

Thanks!

2reactions
jody-zeitlercommented, Feb 28, 2018

I’ve realized I can accomplish what I want by adding left/right margin to the tab itself, so the bounding box is calculated appropriately. Updated sandbox:

capture d ecran 2018-02-28 a 14 46 59

import classnames from "classnames";
import MuiAppBar from "material-ui/AppBar";
import withStyles from "material-ui/styles/withStyles";
import MuiTabs from "material-ui/Tabs/Tabs";
import PropTypes from "prop-types";
import React from "react";

const SEGMENT_MARGIN = 6;

/**
 * Tabs are a composite of a static AppBar and the base Tabs component.
 */
const Tabs = props => {
  const { children, classes, light, segmented, ...otherProps } = props;

  const conditionalClasses = classnames({
    [classes.light]: light,
    [classes.segmented]: segmented
  });
  const appBarClassName = classnames(classes.appBar, conditionalClasses);
  const indicatorClassName = classnames(classes.indicator, conditionalClasses);
  const tabClassName = classnames(classes.tab, conditionalClasses);

  return (
    <MuiAppBar className={appBarClassName} position="static">
      <MuiTabs indicatorClassName={indicatorClassName} {...otherProps}>
        {React.Children.map(children, child => {
          return React.cloneElement(child, {
            "aria-label": child.props["aria-label"] || child.props.label,
            className: classnames(tabClassName, child.props.className)
          });
        })}
      </MuiTabs>
    </MuiAppBar>
  );
};

Tabs.propTypes = {
  /** set of Tab elements */
  children: PropTypes.node,
  /** class overrides */
  classes: PropTypes.shape({
    appBar: PropTypes.string,
    indicator: PropTypes.string
  }),
  /** use light theme colors */
  light: PropTypes.bool,
  /** use segmented selection style instead of underline */
  segmented: PropTypes.bool
};

Tabs.defaultProps = {};

const styles = ({ palette }) => ({
  appBar: {
    backgroundColor: palette.primary.main,
    color: palette.primary.contrastText,
    "&$light": {
      backgroundColor: palette.grey[100],
      color: palette.getContrastText(palette.grey[100]),
      "&$segmented": {
        backgroundColor: palette.grey[200],
        color: palette.getContrastText(palette.grey[200])
      }
    }
  },
  indicator: {
    height: 4,
    backgroundColor: palette.primary.dark,
    "&$light": {
      height: 2,
      backgroundColor: palette.primary.main,
      "&$segmented": {
        backgroundColor: palette.background.paper
      }
    },
    "&$segmented": {
      height: `calc(100% - ${SEGMENT_MARGIN * 2}px)`,
      bottom: SEGMENT_MARGIN,
      borderRadius: 4,
      "&$light": {
        height: `calc(100% - ${SEGMENT_MARGIN * 2}px)`
      }
    }
  },
  light: {},
  segmented: {},
  tab: {
    margin: `0 ${SEGMENT_MARGIN}px`,
    "&$segmented": {
      zIndex: 1
    }
  }
});

export default withStyles(styles)(Tabs);

https://codesandbox.io/s/9z9z4rkjny

Read more comments on GitHub >

github_iconTop Results From Across the Web

How to customise Material UI Tab's indicator width and ...
Default fullwidth tabs. Indicator taking full width of the base button: List item. Width of indicator fixed, but not aligned to center below...
Read more >
Tabs indicator custom width and position #10465 - GitHub
We are creating a component that wraps AppBar and Tabs. It has a segmented option which places the indicator underneath the tab (z-axis)...
Read more >
How To Style MUI Tabs and Tab Indicator - YouTube
Do you want to build a full MUI app from beginning to end, learn every aspect of the sx prop, styled API, and...
Read more >
The Ultimate MUI Tab Indicator Tutorial (Props, Color, Size)
In this demo I will show what values TabIndicatorProps accepts and how to change width, height, and color of the tab indicator.
Read more >
Material UI - Customizing tab indicator - CodeSandbox
Material UI - Customizing tab indicator. 1. Embed Fork Create Sandbox Sign in. Sandbox Info. Material UI - Customizing tab indicator.
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found