How to change the tab indicator color of a tab with a validation error?

Viewed 968

I'm struggling with Material UI styles, for whenever a tab has an invalid field(s).

Here are my styles,

const useTabsClasses = makeStyles(theme => ({
  root: {
    color: theme.palette.common.accent,
    height: '2rem',
  },
  indicator: {
    backgroundColor: theme.palette.common.accent,
  },
  indicatorColor: {
    backgroundColor: theme.palette.common.accent,
  },
}));

const useTabClassesErrorStyles = makeStyles({
  wrapper: {
    color: 'red',
  },
});

const tabsClasses = useTabsClasses();
const tabClassesError = useTabClassesErrorStyles();

And here are my tabs,

<Tabs
  value={tabValue}
  onChange={(event, newValue) => setTabValue(newValue)}
  classes={tabsClasses}
>
  <Tab label="Description" classes={!tabValidate['description'] ? tabClassesError : {}} />
  <Tab label="Cover" classes={!tabValidate['Tab2'] ? tabClassesError : {}} />
</Tabs>

When there are no errors, the text color and the indicator color are blue. As the code is right now, I managed to get the text color of the invalid tab to turn red when that tab has an error:

img1

But how can I change the color of the indicator as well? I want the text and the indicator color to be red.

According to the docs, there is a property called indicator that can be overridden, but that will change the indicator style for all tabs.

Sandbox example of changing tab indicator styles for ALL tabs. However, I want to change the indicator style of only SPECIFIC tabs, not all of them.


Edit

How I solved it for my use case (although, the approach of the accepted answer would have done the job as well, my implementation required a slightly more custom approach).

I added TabIndicatorProps to the <Tabs ... /> component, and dynamically determined the color, because multiple tabs could have had validation errors:

const theme = useTheme(); // hook for material ui

const getTabIndicatorStyle = () => {
  const tabIndicatorColor = theme.palette.error.main;
  switch (tabValue) {
    case 0:
      if (!tabValidate['description']) return tabIndicatorColor;
      break;
    case 1:
      if (!tabValidate['cover']) return tabIndicatorColor;
      break;
    default:
      return '';
  }
};

<Tabs
  value={tabValue}
  onChange={(event, newValue) => setTabValue(newValue)}
  classes={tabsClasses}
  TabIndicatorProps={{
    style: {
      backgroundColor: getTabIndicatorStyle(),
    },
  }}
>
  <Tab label="Description" classes={!tabValidate['description'] ? tabClassesError : {}} />
  <Tab label="Cover" classes={!tabValidate['Tab2'] ? tabClassesError : {}} />
</Tabs>

img2

1 Answers

Write a list of makeStyles would be fine

classes={{ indicator: indicatorList[selected]().indicator }}

enter image description here

If the theme is needed, use useTheme and pass it as params would work.

You can also build a constant color list inside the component with the theme, which would be the same.


Full code:

const indicatorList = ["red", "green", "blue", "black"].map(x =>
  makeStyles(theme => ({
    indicator: {
      // backgroundColor: theme.palette.common.accent
      backgroundColor: x
    }
  }))
);

export default function App() {
  const [selected, setSelected] = useState(0);
  const setTabValue = idx => {
    setSelected(idx);
  };
  return (
    <div className="App">
      <Tabs
        value={selected}
        onChange={(e, idx) => setTabValue(idx)}
        classes={{ indicator: indicatorList[selected]().indicator }}
      >
        <Tab label="Description" />
        <Tab label="Cover" />
        <Tab label="Cover" />
        <Tab label="Cover" />
      </Tabs>
    </div>
  );
}

Edit trusting-swirles-42hnl

Related