Reputation: 553
I have created a Material-UI persistent drawer in which there is a list item component that aims to change the icon color whenever a user clicks on the list item. But my styling is only working with Material-UI icon, not with external SVG.
Here is codesandbox link for the same project to understand it better.
Here is my AppBarDrawer.js
parent component that renders my listItem component. Working fine and can be ignored
import React from "react";
import clsx from "clsx";
import { makeStyles, useTheme } from "@material-ui/core/styles";
import Drawer from "@material-ui/core/Drawer";
import CssBaseline from "@material-ui/core/CssBaseline";
import AppBar from "@material-ui/core/AppBar";
import Toolbar from "@material-ui/core/Toolbar";
import List from "@material-ui/core/List";
import Typography from "@material-ui/core/Typography";
import Divider from "@material-ui/core/Divider";
import IconButton from "@material-ui/core/IconButton";
import MenuIcon from "@material-ui/icons/Menu";
import ChevronLeftIcon from "@material-ui/icons/ChevronLeft";
import ChevronRightIcon from "@material-ui/icons/ChevronRight";
import ListItem from "@material-ui/core/ListItem";
import ListItemIcon from "@material-ui/core/ListItemIcon";
import ListItemText from "@material-ui/core/ListItemText";
import InboxIcon from "@material-ui/icons/MoveToInbox";
import MailIcon from "@material-ui/icons/Mail";
import DrawerList from "./components/DrawerList";
const drawerWidth = 240;
const useStyles = makeStyles((theme) => ({
root: {
display: "flex"
},
appBar: {
transition: theme.transitions.create(["margin", "width"], {
easing: theme.transitions.easing.sharp,
duration: theme.transitions.duration.leavingScreen
})
},
appBarShift: {
width: `calc(100% - ${drawerWidth}px)`,
marginLeft: drawerWidth,
transition: theme.transitions.create(["margin", "width"], {
easing: theme.transitions.easing.easeOut,
duration: theme.transitions.duration.enteringScreen
})
},
menuButton: {
marginRight: theme.spacing(2)
},
hide: {
display: "none"
},
drawer: {
width: drawerWidth,
flexShrink: 0
},
drawerPaper: {
width: drawerWidth
},
drawerHeader: {
display: "flex",
alignItems: "center",
padding: theme.spacing(0, 1),
// necessary for content to be below app bar
...theme.mixins.toolbar,
justifyContent: "flex-end"
},
content: {
flexGrow: 1,
padding: theme.spacing(3),
transition: theme.transitions.create("margin", {
easing: theme.transitions.easing.sharp,
duration: theme.transitions.duration.leavingScreen
}),
marginLeft: -drawerWidth
},
contentShift: {
transition: theme.transitions.create("margin", {
easing: theme.transitions.easing.easeOut,
duration: theme.transitions.duration.enteringScreen
}),
marginLeft: 0
}
}));
export default function PersistentDrawerLeft() {
const classes = useStyles();
const theme = useTheme();
const [open, setOpen] = React.useState(true);
const handleDrawerOpen = () => {
setOpen(true);
};
const handleDrawerClose = () => {
setOpen(false);
};
return (
<div className={classes.root}>
<CssBaseline />
<AppBar
position="fixed"
className={clsx(classes.appBar, {
[classes.appBarShift]: open
})}
>
<Toolbar>
<IconButton
color="inherit"
aria-label="open drawer"
onClick={handleDrawerOpen}
edge="start"
className={clsx(classes.menuButton, open && classes.hide)}
>
<MenuIcon />
</IconButton>
<Typography variant="h6" noWrap>
Persistent drawer
</Typography>
</Toolbar>
</AppBar>
<Drawer
className={classes.drawer}
variant="persistent"
anchor="left"
open={open}
classes={{
paper: classes.drawerPaper
}}
>
<div className={classes.drawerHeader}>
<IconButton onClick={handleDrawerClose}>
{theme.direction === "ltr" ? (
<ChevronLeftIcon />
) : (
<ChevronRightIcon />
)}
</IconButton>
</div>
<Divider />
<List>
<DrawerList />
</List>
</Drawer>
<main
className={clsx(classes.content, {
[classes.contentShift]: open
})}
>
<div className={classes.drawerHeader} />
<Typography paragraph>
Lorem Nulla posuere sollicitudin aliquam ultrices sagittis orci a
</Typography>
</main>
</div>
);
}
The Main file DrawerList.js
which is not giving desired out
Here the real issue is my external icons color is not changing to white whenever I click on it however the last icon named ExitToAppOutlined
is a Material-UI icon and is working fine on click.
import React, { useState } from "react";
import ListItem from "@material-ui/core/ListItem";
import Link from "@material-ui/core/Link";
import ListItemIcon from "@material-ui/core/ListItemIcon";
import { ExitToAppOutlined } from "@material-ui/icons";
import ListItemText from "@material-ui/core/ListItemText";
import { useStyles } from "./DrawerListStyle";
import Typography from "@material-ui/core/Typography";
import Box from "@material-ui/core/Box";
import { SvgIcon } from "@material-ui/core";
import { ReactComponent as Appointment } from "../../assets/Appointment.svg";
import { ReactComponent as Customers } from "../../assets/manage customers 2.svg";
const itemList = [
{
text: "Book Appointment",
icon: (
<SvgIcon>
{/* external icons as svg */}
<Appointment />
</SvgIcon>
)
},
{
text: "Manage",
icon: (
<SvgIcon>
{/* external icons as svg */}
<Customers />
</SvgIcon>
)
},
{
text: "Logout",
// Material Icons
icon: <ExitToAppOutlined />
}
];
const DrawerList = () => {
const [selectedIndex, setSelectedIndex] = useState(0);
const classes = useStyles();
const ListData = () =>
itemList.map((item, index) => {
const { text, icon } = item;
return (
<ListItem
button
key={text}
component={Link}
selected={index === selectedIndex}
onClick={(e) => handleListItemClick(e, index)}
style={selectedIndex === index ? { backgroundColor: "#6A2CD8" } : {}}
>
<ListItemIcon
className={classes.iconStyle}
style={selectedIndex === index ? { color: "#fff" } : {}}
>
{icon}
<ListItemText>
<Typography
component="div"
className={classes.iconTitle}
style={selectedIndex === index ? { color: "#fff" } : {}}
>
<Box fontWeight={500} fontSize={13.5}>
{text}
</Box>
</Typography>
</ListItemText>
</ListItemIcon>
</ListItem>
);
});
const handleListItemClick = (e, index) => {
setSelectedIndex(index);
};
return (
<div className={classes.root}>
<ListData />
</div>
);
};
export default DrawerList;
DrawerListStyle.js
just an stylejs file and can be ignored
import { makeStyles } from "@material-ui/core";
const useStyles = makeStyles((theme) => ({
root: {
marginTop: theme.spacing(2)
},
iconStyle: {
margin: theme.spacing(0, 0, 1, 0),
color: "#6A2CD8"
},
iconTitle: {
margin: theme.spacing(0, 0, 0, 1),
color: "#555458"
}
}));
export { useStyles };
Upvotes: 1
Views: 1529
Reputation: 1504
you can also use SVGR
to build your own icons.
you can follow these steps:
1- install svgr using
npm install --save-dev @svgr/cli
# or use yarn
yarn add --dev @svgr/cli
2- add your icons in public/icons
3- create a file named svgr.config.js
and place it in the root of project
module.exports = {
icon: true,
dimensions: false,
expandProps: false,
replaceAttrValues: {
'#000': 'currentColor',
'#292D32': 'currentColor',
'#292d32': 'currentColor',
'#55BB9D': 'currentColor',
'#FFBC50': 'currentColor',
'#A7A7A7': 'currentColor'
}
};
4- add script in package.json
"svg": "svgr --ext=jsx -d src/@share/icons public/icons"
5 - run yarn svg
.
once you run above command svgr grab all icons in the public folder and gerenate React component inside src/@share/icons
folder based on the config you provided.
and replace every color text of svg into current color.
in this case replace every key in replaceAttrValues
to the currentColor
.
then in your react component you can simply do this:
import { MyIcon } from '@share/icons';
import { SvgIcon } from '@mui/material';
function MyComponent() {
return <p><SvgIcon component={MyIcon} /> check this icon </p>
};
export default MyComponent;
in this way you can change the color the way you change the text color of p
element.
Upvotes: 0
Reputation: 81310
Material-UI sets the color
of your ListItemIcon
when the ListItem
is selected, but because your custom svg
icons already have the fill
attribute set to another color, it overrides the color
from MUI. The fix is simple, override the fill
attribute again in your custom svg using makeStyles
:
const useStyles = makeStyles((theme) => ({
{...}
listItem: {
"&.Mui-selected": {
"& path": {
fill: "white"
}
}
}
}));
<ListItem className={classes.listItem}
Upvotes: 2