Vertical Tabs in React, need to apply custom class on previously active tab

Viewed 52

I have vertical tabs as below, need to apply custom CSS class [completed] on tab which is completed [filled]

return (
    <CustomVerticalTabs theme={theme} className="u-vertical-tabs">
      <Tabs className="tab-list-vertical"
        orientation="vertical"
        variant="scrollable"
        value={value}
        onChange={handleChange}
        aria-label="Vertical tabs example"
        sx={{
          [`& .${tabsClasses.scrollButtons}`]: {
            '&.Mui-disabled': { opacity: 0.3 },
          },
        }}
      >
        {items.map((item, index) => (
          
         <Tab className={`u-tab-btn  ${index === value ? 'completed' :''}`} label={item.title} key={index} />
          
        ))}
      </Tabs>
      {items.map((item, index) => (
        <TabPanel theme={theme} value={value} index={index} key={index}>
          {item.content}
        </TabPanel>
      ))}
    </CustomVerticalTabs>
  )
}

 const handleChange = (event: React.SyntheticEvent, newValue: number) => {
    setValue(newValue)
  }

by applying ${index === value ? completed :or even ${index === value-1 ? completed :it applies to all rest of tabs [except clicked]. I need style to be applied only the previously active tab, but neither the currently active, nor the others (never activated, or before the previous one)

2 Answers

Are you sure that you are using the right form of ${}?

You have this: "u-tab-btn ${index === value ? 'completed' :"
You should use backticks:

`u-tab-btn  ${index === value ? 'completed' :''}` 

If you want to target the "previously active" tab, you need a state to store the information about that previous tab.

Since we already need a state for the currently active tab, (for the normal tabs operation), it means we need an extra state.

We can easily manage it ourself, or we can leverage the usePrevious hook of react-use for example:

React state hook that returns the previous state as described in the React hooks FAQ.

import { usePrevious } from "react-use";

export default function App() {
  const [value, setValue] = React.useState(0);
  const previousValue = usePrevious(value); // State for the previously active tab

  const handleChange = (_: unknown, newValue: number) => {
    setValue(newValue);
  };

  return (
    <div>
      <Tabs
        orientation="vertical"
        variant="scrollable"
        value={value}
        onChange={handleChange}
      >
        {items.map((item, index) => (
          <Tab
            className={`u-tab-btn  ${
              index === value // Active tab
                ? "completed" // Style for the active tab (green in the demo)
                : index === previousValue // Previously active tab
                ? "foo" // Style for the previously active tab (red in the demo)
                : "" // Style for the other tabs (grey in the demo)
            }`}
            label={item.title}
            key={index}
          />
        ))}
      </Tabs>
      {items.map((item, index) => (
        <div key={index}>{item.content}</div>
      ))}
    </div>
  );
}

Demo: https://codesandbox.io/s/vigorous-bessie-wnwywi?file=/src/App.tsx

Related