Signum
Signum

Reputation: 875

ListItemButton as NavLink - apply style when active/selected

I have list of NavLinks:

const users = Array.from(Array(5).keys()).map((key) => ({
    id: key,
    name: `User ${key}`,
}));

<List>
{users.map((user) => {
    return (
        <ListItem disablePadding key={user.id}>
            <ListItemButton
                component={NavLink}
                to={`/messages/${user.id}`}
                sx={{
                    "&.active": {
                        backgroundColor: "lightgray",
                    },
                }}
            >
                <ListItemIcon>
                    <PersonIcon />
                </ListItemIcon>
                <ListItemText primary={user.name}></ListItemText>
            </ListItemButton>
        </ListItem>
    );
})}
</List>

The problem is that I have to manually specify the style of active link and hardcode backgroundColor. When I remove sx style from the component, link doesn't look like it's active. Why it doesn't automatically change the background color when active?

Upvotes: 1

Views: 967

Answers (1)

Drew Reese
Drew Reese

Reputation: 203373

The ListItemButton extends the base button component, neither of which have any default styling for an added "active" CSS classname. When actually rendering the NavLink component as the ListItemButton.component then the NavLink component applies a "active" class, but the default link styling is overridden/set by the base button and ListItemButton styling.

NavLink

By default, an active class is added to a <NavLink> component when it is active. This provides the same simple styling mechanism for most users who are upgrading from v5. One difference as of v6.0.0-beta.3 is that activeClassName and activeStyle have been removed from NavLinkProps. Instead, you can pass a function to either style or className that will allow you to customize the inline styling or the class string based on the component's active state.

The default background color is "transparent", and the "active" is overriding it.

enter image description here

The ListItemButton's sx prop is setting the styling for the "active" class and has higher CSS selector specificity.

An alternative way to apply CSS for the ListItemButton/NavLink is to use the NavLink's style function prop:

<List>
  {users.map((user) => {
    return (
      <ListItem disablePadding key={user.id}>
        <ListItemButton
          component={NavLink}
          to={`/messages/${user.id}`}
          style={({ isActive }) => isActive ? {
            backgroundColor: "lightgray"
          } : null}
        >
          <ListItemIcon>
              <PersonIcon />
          </ListItemIcon>
          <ListItemText primary={user.name}></ListItemText>
        </ListItemButton>
      </ListItem>
    );
  })}
</List>

Upvotes: 2

Related Questions