I'm using Material-UI v5 and trying to migrate to using styled instead of makeStyles because it seems as though that's the "preferred" approach now. I understand using makeStyles is still valid but I'm trying to embrace the new styling solution instead.
I've got a list of list items which represent navigation links, and I want to highlight the one that's currently selected. Here's how I did this using makeStyles:
interface ListItemLinkProps {
label: string;
to: string;
}
const useStyles = makeStyles<Theme>(theme => ({
selected: {
color: () => theme.palette.primary.main,
},
}));
const ListItemLink = ({ to, label, children }: PropsWithChildren<ListItemLinkProps>) => {
const styles = useStyles();
const match = useRouteMatch(to);
const className = clsx({ [styles.selected]: !!match });
return (
<ListItem button component={Link} to={to} className={className}>
<ListItemIcon>{children}</ListItemIcon>
<ListItemText primary={label} />
</ListItem>
);
};
(Note here I'm using clsx to determine if the selected style should be applied to the ListItem element.)
How do I achieve this using styled? This is what I've come up with so far (note: the interface for ListItemLinkProps hasn't changed so I haven't repeated it here):
const LinkItem = styled(ListItem, {
shouldForwardProp: (propName: PropertyKey) => propName !== 'isSelected'
})<ListItemProps & LinkProps & { isSelected: boolean }>(({ theme, isSelected }) => ({
...(isSelected && { color: theme.palette.primary.main }),
}));
const ListItemLink = ({ to, label, children }: PropsWithChildren<ListItemLinkProps>) => {
const match = useRouteMatch(to);
return (
// @ts-ignore
<LinkItem button component={Link} to={to} isSelected={!!match}>
<ListItemIcon>{children}</ListItemIcon>
<ListItemText primary={label} />
</LinkItem>
);
};
So, two questions about this:
Is this best way to do a conditional style?
The other problem is that I can't work out the correct types for the
styleddeclaration - I have to put the// @ts-ignorecomment above theLinkItembecause of the way its types are declared.