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.
The Tabs indicator is locked to the left
and width
of the currently selected tab's getBoundingClientRect
.
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
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.
| Tech | Version |
|--------------|---------|
| Material-UI | 1.0.0-beta.34 |
| React | 16.2.0 |
| browser | Chrome 64 |
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:
@jody-zeitler The indicator is rendered two different ways. One that is during for the server-sider rendering and one that is absolute for transitioning the active tab. Fixing both requirement might be challenging.
I'll look into the server-side aspect of it and see what might work.
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:
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);
@jody-zeitler where is the document about your custom code? I want to custom the width and left value of the red underline line too. Thanks a lot.
@wufeng87 width and left are calculated based on the bounding box of the selected tab. I couldn't find a good way to alter them directly so I applied a margin to the tab to achieve the look that I was aiming for. I was able to apply bottom
and height
directly to the indicator as those properties are not overridden by inline styles.
@jody-zeitler thanks. I moved to v1.0.0-beta, hope I could find a way to custom the indicator width.
We now demonstrate a tab customization example in the documentation: https://material-ui-next.com/demos/tabs/#customized-tabs.
@wufeng87 Were you able to find a way to access the default left value of the selected tab? I'd like to shrink the TabIndicator and centre it using the left value, but I don't see any way to access the left and width values as suggested in the issue.
@HiranmayaGundu Do you have a visual example? Maybe I can help.
@oliviertassinari This is what I was aiming for
@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);
Thanks!
@oliviertassinari Thanks for the prompt reply! I'll add it to the docs.
Was this intended behaviour for TabIndicatorProps? My understanding was that it was another option to style the Indicator, other than using the override.
@HiranmayaGundu I don't understand your point regarding the TabIndicatorProps
property.
@oliviertassinari I think they were asking whether *Props properties being used to override children is intended behaviour
Yes, the indicator doesn't have any children we provide one.
How exactly do we style the indicator? TypeScript tells me I am not allowed to pass a indicator
property into the classes
prop of Tab
.
Oh, I see, indicator
must be supplied to the Tabs
component, not to each Tab
. It may be confusing at first, but makes sense that the indicator is not actually inside the tabs, just one underneath all tabs.
I want to customize the tab bar something like this with curve borders. Please see the attached screenshot. Can anyone help me out please
Most helpful comment
@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
Thanks!