The Best MUI Tabs Tutorial: Hover, Active, Focus, and onClick

Material-UI Tabs are composed of several components: the Tabs component, child Tab components, and usually a container and tab panel. We can quickly add perfect styling to these elements with the sx prop and some nested selectors.

Additionally, I will show the difference in Tab onClick, Tabs onChange, and which one is best to use.

MUI Tabs hover, active, and focus styling
MUI Tabs hover, active, and focus styling

The Resources section has a link to a live Code Sandbox demo. A YouTube version of this post is here.

Here are additional useful links:

MUI Tab Hover, Active, and Focus Color

The two components we are most interested in are MUI Tabs and individual MUI Tab components (it’s confusing!). The Tabs component is a wrapper that renders three divs deep to handle horizontal scrolling. Each Tab renders as a single button element that wraps a span.

MUI Tabs DOM

It is important to avoid redundant styling code on each Tab. Instead, we could create a styled Tabs component or add selectors to the Tabs sx prop that target all Tab buttons. Either is a fine choice; I added selectors to the Tabs sx in the code below.

<Tabs
  value={value}
  onChange={handleChange}
  sx={{
    "& button": { borderRadius: 2 },
    "& button:hover": { backgroundColor: "blue" },
    "& button:focus": { backgroundColor: "yellow" },
    "& button:active": { backgroundColor: "green" }
  }}
>
  <Tab label="Item One" />
  <Tab label="Item Two" />
  <Tab label="Item Three" />
</Tabs>

These selectors show why it is important to know how MUI renders in the DOM. Without exploring the DOM, we might not know that a Tab renders as a button.

I first selected all buttons within the Tabs component and gave them a border radius. There is no default styling on a Tab so this is invisible until the Tab is selected.

Notice the syntax for Tab hover. The empty space after & means that it selects a child element. The button:hover syntax is the pseudo selector syntax.

The Tab active and focus syntax is the same as the hover syntax because they are also pseudo classes applied by the browser when the relevant pointer event occurs.

The focus pseudo class is applied by the browser when the Tab gets focus. This can occur by a tab keyboard event or by a mouse click. The active pseudo class is applied immediately when the user clicks down (mouse down event) on the tab, and stays applied until the click is let up (mouse up).

In my example code, the focus selector is above the active selector. This means in the brief moment during a click when both active and focus are applied, active styling will override focus styling. Code order matters!

After mouse up occurs, the Tab will still have focus until a new element gets focus. However, the Mui-selected class is applied be default on click of the tab and remains on the tab. Mui-selected can be used to style the selected tab after the focus class is no longer applied by the browser.

MUI Tab onClick vs Tabs onChange (With TypeScript)

The Tab onClick event passes only one value: the DOM event. It is possible to dig into this parameter and extract a useful value, but instead I recommend using the Tabs onChange handler. This passes the DOM event and a tab index value.

MUI Tab Event
MUI Tab Event

In the example code below you can see the TypeScript typing of the ChangeEvent and MouseEvent (the click event). The value is a state value for controlling which tab panel is visible.

const [value, setValue] = React.useState(0);

const handleChange = (event: React.ChangeEvent<{}>, newValue: number) => {
  setValue(newValue);
  console.log(`value: ${newValue}`);
};

const handleClick = (event: React.MouseEvent) => {
  console.log(event);
};

//JSX
<Tabs
  value={value}
  onChange={handleChange}
>
  <Tab onClick={handleClick} />
  <Tab onClick={handleClick} />
  <Tab onClick={handleClick}/>
</Tabs>

Resources

MUI Tabs Docs

Code Sandbox link

Share this post:

Leave a Comment

This site uses Akismet to reduce spam. Learn how your comment data is processed.