ForwardRef error in Chakra-ui when wrapping IconButton component - reactjs

I created a reusable component that wraps the IconButton and pass as one of the props icons from react-icons.
I get the following error:
Warning: Function components cannot be given refs. Attempts to access
this ref will fail. Did you mean to use React.forwardRef()?`
Here's my component wrapper:
export function SidebarMenu({ icon, isActive, handleMenuClick, name }) {
return (
<IconButton
className={isActive ? 'active' : ''}
aria-label={name + ' menu'}
isActive={isActive}
bg="transparent"
px="0"
as={icon}
_hover={{
cursor: 'pointer',
backgroundColor: 'transparent',
}}
_active={{
backgroundColor: 'transparent',
}}
onClick={() => handleMenuClick(name)}
/>
Here's how i use the wrapper component
<SidebarMenu
icon={VscCode}
name="folders"
handleMenuClick={handleMenuClick}
isActive={menuList.folders}
/>
But if i change the content IconButton to a instead use a Icon wrapped in a Button the error disappears.
export function SidebarMenu({ icon, isActive, handleMenuClick, name }) {
return (
<Button
className={isActive ? 'active' : ''}
aria-label={name + ' menu'}
isActive={isActive}
bg="transparent"
px="0"
// as={icon}
_hover={{
cursor: 'pointer',
backgroundColor: 'transparent',
}}
_active={{
backgroundColor: 'transparent',
}}
onClick={() => handleMenuClick(name)}
>
<Icon as={icon} w={7} h={7} />
</Button>
);
}
Edit:
For anyone who may stumble on the same problem.
There are couple of things i did wrong here.
I was using as instead of icon prop in IconButton
Second, i was passing a reference instead of the component
Instead of doing <IconButton icon={<VsColorMode />} />, i was doing this <IconButton icon={VsCodeMode} />.

According to the doc, IconButton has its own prop icon, so instead of using as, in this case, use icon with Icon
function SidebarMenu({ icon }) {
return (
<IconButton
bg="transparent"
px="0"
icon={<Icon as={icon} w={7} h={7} />}
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
_hover={{
cursor: "pointer",
backgroundColor: "transparent"
}}
_active={{
backgroundColor: "transparent"
}}
/>
);
}
Codesandbox demo

Related

IconButton Hovering Effect on Material UI

below i have different icons from material UI , which currently displays a grey circle whenever i hover on any of them , i want to remove this grey circle and i want each icon to change to a specific color whenever i hover over it i looked at the documentation in material ui but couldn't find anything that explains it , appreciate your feedback.
<Box className={classes.socialmedia}>
<IconButton aria-label="twitter">
<TwitterIcon />
</IconButton>
<IconButton aria-label="facebook">
<FacebookIcon />
</IconButton>
<IconButton aria-label="instagram">
<InstagramIcon />
</IconButton>
<IconButton aria-label="Youtube">
<YouTubeIcon />
</IconButton>
<IconButton aria-label="Apple">
<AppleIcon />
</IconButton>
</Box>
In order to remove the grey circle displaying in background on hover then you can use disableFocusRipple & disableRipple property in IconButton component and set style={{ backgroundColor: 'transparent' }}.
Ex:
<IconButton
disableFocusRipple
disableRipple
style={{ backgroundColor: "transparent" }}
aria-label="twitter"
>
<TwitterIcon className={classes.twitter} />
</IconButton>
To change the color of icon on hover then use hover selector.
Ex:
const useStyles = makeStyles({
twitter: {
"&:hover": {
color: "#00acee"
}
}
});
I've created a quick example to illustrate the solution in codesandbox:
https://codesandbox.io/s/elegant-ramanujan-wnj9fw?file=/index.js:948-961
Define a hook. Import makeStyle from '#material-ui/core/styles'.
const useStyles = makeStyle(() => ({
styleRed: {
'&:hover': {
backgroundColor: '#f00'
}
},
styleBlue: {
'&:hover': {
backgroundColor: '#00f'
}
}
}));
Then in your component:
// using our hook
const {styleRed, styleBlue} = useStyles();
// some more code
return (
<>
<IconButton aria-label="twitter" classes={styleRed}>
<TwitterIcon />
</IconButton>
<IconButton aria-label="facebook" classes={styleBlue}>
<FacebookIcon />
</IconButton>
</>
)

MaterialUI React duplicate keys error from mui components

While creating a navbar I used multiple collapse components from MUI in order to create generate the menu items.
Its not a code breaking error but an annoying to have one. I get the following error in my console.
Warning: Encountered two children with the same key, `indexCollapseListItem`. Keys should be unique so that components maintain their identity across updates. Non-unique keys may cause children to be duplicated and/or omitted — the behavior is unsupported and could change in a future version.
div
./node_modules/#emotion/react/dist/emotion-element-699e6908.browser.esm.js/withEmotionCache/<#http://localhost:3000/static/js/bundle.js:5079:66
List#http://localhost:3000/static/js/bundle.js:18632:82
div
./node_modules/#emotion/react/dist/emotion-element-699e6908.browser.esm.js/withEmotionCache/<#http://localhost:3000/static/js/bundle.js:5079:66
div
./node_modules/#emotion/react/dist/emotion-element-699e6908.browser.esm.js/withEmotionCache/<#http://localhost:3000/static/js/bundle.js:5079:66
div
./node_modules/#emotion/react/dist/emotion-element-699e6908.browser.esm.js/withEmotionCache/<#http://localhost:3000/static/js/bundle.js:5079:66
Transition#http://localhost:3000/static/js/bundle.js:102860:30
Collapse#http://localhost:3000/static/js/bundle.js:12704:82
nav
./node_modules/#emotion/react/dist/emotion-element-699e6908.browser.esm.js/withEmotionCache/<#http://localhost:3000/static/js/bundle.js:5079:66
List#http://localhost:3000/static/js/bundle.js:18632:82
div
div
./node_modules/#emotion/react/dist/emotion-element-699e6908.browser.esm.js/withEmotionCache/<#http://localhost:3000/static/js/bundle.js:5079:66
Paper#http://localhost:3000/static/js/bundle.js:22524:82
./node_modules/#emotion/react/dist/emotion-element-699e6908.browser.esm.js/withEmotionCache/<#http://localhost:3000/static/js/bundle.js:5079:66
div
./node_modules/#emotion/react/dist/emotion-element-699e6908.browser.esm.js/withEmotionCache/<#http://localhost:3000/static/js/bundle.js:5079:66
Drawer#http://localhost:3000/static/js/bundle.js:13680:83
nav
./node_modules/#emotion/react/dist/emotion-element-699e6908.browser.esm.js/withEmotionCache/<#http://localhost:3000/static/js/bundle.js:5079:66
Box#http://localhost:3000/static/js/bundle.js:29040:72
div
./node_modules/#emotion/react/dist/emotion-element-699e6908.browser.esm.js/withEmotionCache/<#http://localhost:3000/static/js/bundle.js:5079:66
Box#http://localhost:3000/static/js/bundle.js:29040:72
NavBar#http://localhost:3000/static/js/bundle.js:1766:7
Dashboard
Routes#http://localhost:3000/static/js/bundle.js:101977:7
Router#http://localhost:3000/static/js/bundle.js:101914:7
BrowserRouter#http://localhost:3000/static/js/bundle.js:101391:7
App
Provider#http://localhost:3000/static/js/bundle.js:98572:15 react-dom.development.js:67
React 19
js index.js:8
factory react refresh:6
Webpack 3
Warning: Encountered two children with the same key, `indexCollapseListItem`. Keys should be unique so that components maintain their identity across updates. Non-unique keys may cause children to be duplicated and/or omitted — the behavior is unsupported and could change in a future version.
div
./node_modules/#emotion/react/dist/emotion-element-699e6908.browser.esm.js/withEmotionCache/<#http://localhost:3000/static/js/bundle.js:5079:66
List#http://localhost:3000/static/js/bundle.js:18632:82
div
./node_modules/#emotion/react/dist/emotion-element-699e6908.browser.esm.js/withEmotionCache/<#http://localhost:3000/static/js/bundle.js:5079:66
div
./node_modules/#emotion/react/dist/emotion-element-699e6908.browser.esm.js/withEmotionCache/<#http://localhost:3000/static/js/bundle.js:5079:66
div
./node_modules/#emotion/react/dist/emotion-element-699e6908.browser.esm.js/withEmotionCache/<#http://localhost:3000/static/js/bundle.js:5079:66
Transition#http://localhost:3000/static/js/bundle.js:102860:30
Collapse#http://localhost:3000/static/js/bundle.js:12704:82
nav
./node_modules/#emotion/react/dist/emotion-element-699e6908.browser.esm.js/withEmotionCache/<#http://localhost:3000/static/js/bundle.js:5079:66
List#http://localhost:3000/static/js/bundle.js:18632:82
div
div
./node_modules/#emotion/react/dist/emotion-element-699e6908.browser.esm.js/withEmotionCache/<#http://localhost:3000/static/js/bundle.js:5079:66
Paper#http://localhost:3000/static/js/bundle.js:22524:82
./node_modules/#emotion/react/dist/emotion-element-699e6908.browser.esm.js/withEmotionCache/<#http://localhost:3000/static/js/bundle.js:5079:66
Transition#http://localhost:3000/static/js/bundle.js:102860:30
Slide#http://localhost:3000/static/js/bundle.js:24602:7
Unstable_TrapFocus#http://localhost:3000/static/js/bundle.js:8464:7
div
./node_modules/#emotion/react/dist/emotion-element-699e6908.browser.esm.js/withEmotionCache/<#http://localhost:3000/static/js/bundle.js:5079:66
Portal#http://localhost:3000/static/js/bundle.js:8032:7
ModalUnstyled#http://localhost:3000/static/js/bundle.js:7245:7
Modal#http://localhost:3000/static/js/bundle.js:21375:82
./node_modules/#emotion/react/dist/emotion-element-699e6908.browser.esm.js/withEmotionCache/<#http://localhost:3000/static/js/bundle.js:5079:66
Drawer#http://localhost:3000/static/js/bundle.js:13680:83
nav
./node_modules/#emotion/react/dist/emotion-element-699e6908.browser.esm.js/withEmotionCache/<#http://localhost:3000/static/js/bundle.js:5079:66
Box#http://localhost:3000/static/js/bundle.js:29040:72
div
./node_modules/#emotion/react/dist/emotion-element-699e6908.browser.esm.js/withEmotionCache/<#http://localhost:3000/static/js/bundle.js:5079:66
Box#http://localhost:3000/static/js/bundle.js:29040:72
NavBar#http://localhost:3000/static/js/bundle.js:1766:7
Dashboard
Routes#http://localhost:3000/static/js/bundle.js:101977:7
Router#http://localhost:3000/static/js/bundle.js:101914:7
BrowserRouter#http://localhost:3000/static/js/bundle.js:101391:7
App
Provider#http://localhost:3000/static/js/bundle.js:98572:15 react-dom.development.js:67
​I am not setting this key in my code but why is it being set by default, which component is being assigned the same key again and again and how can I fix this.
My navbar code is the following for your reference.
//ASSETS
import AuraLogo from '../../../assets/images/logo/aura.png'
//REACT
import { useState } from 'react'
import { Link } from 'react-router-dom'
//MenuItems
import menuItems from '../dashboard/menu-items/index'
//MUI
import PropTypes from 'prop-types'
import AppBar from '#mui/material/AppBar'
import Box from '#mui/material/Box'
import CssBaseline from '#mui/material/CssBaseline'
import Divider from '#mui/material/Divider'
import Drawer from '#mui/material/Drawer'
import IconButton from '#mui/material/IconButton'
import List from '#mui/material/List'
import ListItemIcon from '#mui/material/ListItemIcon'
import ListItemText from '#mui/material/ListItemText'
import MenuIcon from '#mui/icons-material/Menu'
import Toolbar from '#mui/material/Toolbar'
import Typography from '#mui/material/Typography'
import Collapse from '#mui/material/Collapse'
import ListSubheader from '#mui/material/ListSubheader'
import ListItemButton from '#mui/material/ListItemButton'
import ExpandLess from '#mui/icons-material/ExpandLess'
import ExpandMore from '#mui/icons-material/ExpandMore'
import ArrowBackIosNew from '#mui/icons-material/ArrowBackIosNew'
const drawerWidth = 240
// TODO - fix duplicate keys error in components from MUI
function NavBar(props) {
const { window } = props
const [mobileOpen, setMobileOpen] = useState(false)
// TODO - change appbar title depending on the category clicked
const [title, setTitle] = useState()
const [open, setOpen] = useState({
dashboard: true,
categories: true,
subcategories: true,
products: true,
auth: true,
other: false,
})
const handleClick = (id) => {
setOpen((prevState) => ({ ...prevState, [id]: !prevState[id] }))
}
// const handleClick = (id) => {
// setOpen({ ...state, [id]: !open[id] });
// // setOpen((prevState => ({...prevState, [id]: !prevState[id]}))
// };
// const handleClick = (item) => {
// setOpen({
// item : !open
// })
// }
const handleDrawerToggle = () => {
setMobileOpen(!mobileOpen)
}
const drawer = (
<div>
<Toolbar key={'LogoToolbar'}>
<img
as={Link}
src={AuraLogo}
style={{
maxWidth: '60%',
maxHeight: '60%',
paddingTop: '10px',
paddingBottom: '10px',
margin: '0 auto',
}}
/>
</Toolbar>
<Divider />
{menuItems.items.map(({id, icon, title, children}) => (
<>
<List
key={id+'ParentList'}
sx={{ width: '100%', maxWidth: 360, bgcolor: 'background.paper' }}
component='nav'
aria-labelledby='nested-list-subheader'
// subheader={
// <ListSubheader component='div' id='nested-list-subheader'>
// {item.subheader}
// </ListSubheader>
// }
>
<ListItemButton key={id+'listitembutton'} onClick={() => handleClick(id)}>
<ListItemIcon>{icon}</ListItemIcon>
<ListItemText primary={title} />
{open[id] ? <ExpandLess /> : <ExpandMore />}
</ListItemButton>
<Collapse key={id+'collapse'} in={open[id]} timeout='auto' unmountOnExit>
<List key={id+'listchildren'} component='div' disablePadding>
{children.map(({id, icon, title, url}) => (
<ListItemButton
component={Link}
to={`${url}`}
onClick={handleDrawerToggle}
key={id+'CollapseListItem'}
sx={{ pl: 3 }}>
<ListItemIcon>{icon}</ListItemIcon>
<ListItemText primary={title} />
</ListItemButton>
))}
</List>
</Collapse>
</List>
<Divider />
</>
))}
<Link style={{textDecoration: 'none', color: '#202020'}} to='/'>
<ListItemButton key={'returnlistitembutton'}>
<ListItemIcon><ArrowBackIosNew/></ListItemIcon>
<ListItemText primary='Πίσω στους καταλόγους' />
</ListItemButton>
</Link>
</div>
)
const container =
window !== undefined ? () => window().document.body : undefined
return (
<Box sx={{ display: 'flex' }}>
<CssBaseline />
<AppBar
position='fixed'
sx={{
width: { sm: `calc(100% - ${drawerWidth}px)` },
ml: { sm: `${drawerWidth}px` },
}}>
<Toolbar>
<IconButton
color='inherit'
aria-label='open drawer'
edge='start'
onClick={handleDrawerToggle}
sx={{ mr: 2, display: { sm: 'none' } }}>
<MenuIcon />
</IconButton>
<Typography variant='h6' noWrap component='div'>
Dashboard
{/* TODO - add more functionallity to appbar */}
</Typography>
</Toolbar>
</AppBar>
<Box
component='nav'
sx={{ width: { sm: drawerWidth }, flexShrink: { sm: 0 } }}
aria-label='mailbox folders'>
{/* The implementation can be swapped with js to avoid SEO duplication of links. */}
<Drawer
key={'drawer'}
container={container}
variant='temporary'
open={mobileOpen}
onClose={handleDrawerToggle}
ModalProps={{
keepMounted: true, // Better open performance on mobile.
}}
sx={{
display: { xs: 'block', sm: 'none' },
'& .MuiDrawer-paper': {
boxSizing: 'border-box',
width: drawerWidth,
},
}}>
{drawer}
</Drawer>
<Drawer
variant='permanent'
sx={{
display: { xs: 'none', sm: 'block' },
'& .MuiDrawer-paper': {
boxSizing: 'border-box',
width: drawerWidth,
},
}}
open>
{drawer}
</Drawer>
</Box>
<Box
component='main'
sx={{
flexGrow: 1,
p: 3,
width: { sm: `calc(100% - ${drawerWidth}px)` },
}}>
<Toolbar />
{props.children}
</Box>
</Box>
)
}
NavBar.propTypes = {
/**
* Injected by the documentation to work in an iframe.
* You won't need it on your project.
*/
window: PropTypes.func,
}
export default NavBar
The random key properties that appear almost everywhere was my quest in finding which component generates this error but with no luck.
As always thanks in advance and if by any chance you have any suggestions or solutions... I'm all ears!
You can try something like this.
<List
sx={{ width: '100%', maxWidth: 360, bgcolor: 'background.paper' }}
component='nav'
aria-labelledby='nested-list-subheader'
>
{menuItems.items.map(({id, icon, title, children}, idx) => (
<ListItemButton
onClick={() => handleClick(id)}
key={idx}
>
<ListItemIcon>
{icon}
</ListItemIcon>
<ListItemText
primary={title}
/>
{open[id] ? <ExpandLess /> : <ExpandMore />}
</ListItemButton>
<Collapse in={open[id]} timeout='auto' unmountOnExit>
<List component='div' disablePadding>
{children.map(({id, icon, title, url}, subidx) => (
<ListItemButton
component={Link}
to={`${url}`}
onClick={handleDrawerToggle}
key={subidx}
sx={{ pl: 3 }}
>
<ListItemIcon>
{icon}
</ListItemIcon>
<ListItemText
primary={title}
/>
</ListItemButton>
))}
</List>
</Collapse>
))}
</List>
Here :
{menuItems.items.map(({id, icon, title, children}) => (
<>
<List
key={id+'ParentList'}
Your key must be provide on the first child, in your case the React Fragment so :
{menuItems.items.map(({id, icon, title, children}) => (
<Fragment key={id+'ParentList'}>
<List ...
You need to put a uniq key, the index from map can provide the same issue if you use 2 times (0, 1, 2, 3 === 0, 1, 2, 3), you can use an add string or you can use a methods to generate an uniq key :
uuid nom package
nanoid from redux-toolkit (perfect if you use Redux, don't install it just for that)
create a method from Math.random like Math.floor(Math.random()*10000000).toString(16) ( => hexa key)
create a method from a prefix you give in method params and adding an element from a new Date() or timestamp
...
With this, you sure to create a new and uniq key.
With time, in order, I prefer Nanoid or Math random.

How to change font size of material ui badge content in reactjs?

I want to change the font size of the label in material ui badge.
I am using style={{ fontSize: "15" }} but that only affect its child, which is an icon.
Code:
<Badge badgeContent={props.cartCount} color="secondary" style={{ fontSize: "15" }}>
<ShoppingCart className={classes.mediumIcon} />
</Badge>
Ideal way would be use classes badge as mentioned in documentation
import { Badge } from "#material-ui/core";
import { makeStyles } from "#material-ui/core/styles";
import "./styles.css";
const useStyles = makeStyles((theme) => ({
badge: {
fontSize: 30
}
}));
export default function App() {
const classes = useStyles();
return (
<div className="App">
<h1>Hello CodeSandbox</h1>
<h2>Start editing to see some magic happen!</h2>
<Badge
badgeContent={"h"}
color="secondary"
classes={{ badge: classes.badge }}
/>
</div>
);
}
If you use mui system then this can change badge font size
<Badge
badgeContent={9}
color="error"
overlap="circular"
sx={{ "& .MuiBadge-badge": { fontSize: 9, height: 15, minWidth: 15 } }}
>
<IconButton sx={{ p: 0, color: "primary.main" }}>
<Notifications />
</IconButton>
</Badge>
You can modify the font-size as below.
create styles of different font-size in useStyles
const useStyles = makeStyles((theme) => ({
font1: {
fontSize: "1rem"
},
)}
And then assign it as below to the Badge component
<Badge
classes={{
badge: classes.font1
}}
badgeContent={99}
{...defaultProps}
/>
Sandbox
You can use the componentProps attribute as follows (this example changes the color of the text in the badge but the same principle will work for fontSize).
<Badge badgeContent={comments} componentsProps={{ root: {style: {color: 'white'}} }}>
<CommentIcon />
</Badge>

How to set Material UI Fab to Outline

Is there a way to use the outline variant for the fab button in material ui
<Fab variant="here i see rounded || extended" color="primary" size="small" aria-label="scroll back to top">
<KeyboardArrowUp />
</Fab>
is there a way i could use the outline version and still inherit material ui ripple effect and other styles
As far as I know you cannot have outline version for that. But you can always write CSS for that. I had a simple demo for this
Edit: here are the code
const useStyles = makeStyles((theme: Theme) =>
createStyles({
root: {
"& > *": {
margin: theme.spacing(1)
}
},
fabStyle: {
backgroundColor: "white",
color: theme.palette.primary.light,
borderColor: theme.palette.primary.light,
"&:hover": {
backgroundColor: theme.palette.primary.light,
color: "white"
}
}
})
);
export default function FloatingActionButtons() {
const classes = useStyles();
return (
<div className={classes.root}>
<Fab color="primary" aria-label="add" className={classes.fabStyle}>
<AddIcon />
</Fab>
</div>
);
}
You should be able to inject classes into the Fab component. You can refer to this link for more information Customizing Components
<Fab
classes={{
root: classes.root, // class name, e.g. `classes-nesting-root-x`
label: classes.label, // class name, e.g. `classes-nesting-label-x`
}}
variant="here i see rounded || extended" color="primary" size="small" aria-label="scroll back to top">
<KeyboardArrowUp />
</Fab>

Is there a way I can overwrite the colour the Material UI Icons npm package provides in React?

I am new to React and am using the npm package Material UI icons (https://www.npmjs.com/package/#material-ui/icons) and displaying icons within a React component as such:
Importing:
import KeyboardArrowRightIcon from 'material-ui/svg-icons/hardware/keyboard-arrow-right';
and rendering:
readMoreLink={<a href={someUrl} >Read more <KeyboardArrowRightIcon /></a>}
However, since KeyboardArrowRightIcon is an SVG provided by the npm package, it comes with it's own fill colour:
Eg: <svg viewBox="0 0 24 24" style="display: inline-block; color: rgba(0, 0, 0, 0.54);...
I know I can override this colour by having a style attribute within the element, eg:
<KeyboardArrowRightIcon style={{ fill: '#0072ea' }} />
But is there anyway to make this a SCSS variable (style={{ fill: $link-color }})?
I worry if the link colour changes in the style sheet someone will have to hunt down all these hard coded instances later.
Change Icon Color
<HomeIcon />
<HomeIcon color="primary" />
<HomeIcon color="secondary" />
<HomeIcon color="action" />
<HomeIcon color="disabled" />
<HomeIcon style={{ color: green[500] }} />
<HomeIcon style={{ color: 'red' }} />
Change Icon Size
<HomeIcon fontSize="small" />
<HomeIcon />
<HomeIcon fontSize="large" />
<HomeIcon style={{ fontSize: 40 }} />
MDI using Icon component
<Icon>add_circle</Icon>
<Icon color="primary">add_circle</Icon>
<Icon color="secondary">add_circle</Icon>
<Icon style={{ color: green[500] }}>add_circle</Icon>
<Icon fontSize="small">add_circle</Icon>
<Icon style={{ fontSize: 30 }}>add_circle</Icon>
For the Font
<Icon className="fa fa-plus-circle" />
<Icon className="fa fa-plus-circle" color="primary" />
<Icon className="fa fa-plus-circle" color="secondary" />
<Icon className="fa fa-plus-circle" style={{ color: green[500] }} />
<Icon className="fa fa-plus-circle" fontSize="small" />
<Icon className="fa fa-plus-circle" style={{ fontSize: 30 }} />
Resouces to learn more abo it, Icons
Just add a style fill: "green"
Example: <Star style={{fill: "green"}}/>
The simplest way to specify/override the color of an Icon in Material-UI is to use a custom CSS class name.
Suppose that you want to show a green checkbox rather than a red triangle, depending on the outcome of some process.
You create a function somewhere inside your code, for example like this:
function iconStyles() {
return {
successIcon: {
color: 'green',
},
errorIcon: {
color: 'red',
},
}
}
You then apply makeStyles to that function, and run the result.
import { makeStyles } from '#material-ui/core/styles';
...
const classes = makeStyles(iconStyles)();
Inside your render function, you can now use the object classes:
const chosenIcon = outcome
? <CheckCircleIcon className={classes.successIcon} />
: <ReportProblemIcon className={classes.errorIcon} />;
The function I mentioned first in this answer actually accepts a theme as input and allows you to modify/enrich that theme: this ensures that your custom classes aren't seen as exceptions, but rather as integrations inside a more comprehensive visual solution (for example, icon colors in a theme are best seen as encodings).
Material-UI is very rich and I'd encourage you to explore also other existing customisation mechanisms.
Update: 2022 July MUI5
There are multiple ways to change icon color
<HomeIcon sx={{color: "#FC0"}} />
<HomeIcon htmlColor="red" />
<HomeIcon color="primary" />
<HomeIcon color="success" />
<HomeIcon color="action" />
<HomeIcon color="disabled" />
<HomeIcon color="error" />
<HomeIcon sx={{ color: pink[500] }} />
Using sx prop you can specify any hex/rgb color code or colors from your theme palette
Example :
import { red } from '#mui/material/colors';
<HomeIcon sx={{ color: red[800] }} />
This is what I do
I use MUI v4.5.1. Use the color prop API with value inherit and add a div or span wrapper around and add your color there.
From the API docs
color default value:inherit. The color of the component. It supports those theme colors that make sense for this component.
Add star icon
import React from 'react';
import Star from '#material-ui/icons/StarRounded';
import './styles.css';
export function FavStar() {
return (
<div className="star-container">
<Star size="2em" fontSize="inherit" />
</div>
);
}
In style.css
.star-container {
color: red;
font-size: 30px;
}
You can do like this: <PlusOne htmlColor="#ffaaee" />
The simplest way I found is using the following.
import { styled } from '#material-ui/styles';
import { Visibility } from '#material-ui/icons';
const MyVisibility = styled(Visibility)({
color: 'white',
});
You can set a default color for all icons by creating a custom theme with createMuiTheme():
createMuiTheme({
props: {
MuiSvgIcon: {
htmlColor: '#aa0011',
}
}
})
This will set the default value of the htmlColor prop for every icon like <KeyboardArrowRightIcon/>. Here's a list of other props you can set.
Overwriting the material UI Icon color like below
in js
const [activeStar, setActiveStar] = useState(false);
<IconButton onClick={() => setActiveStar(!activeStar)}>
{activeStar ? (
<StarOutlined className="starBorderOutlined" />
) : (
<StarBorderOutlined />
)}
</IconButton>
in Css
.starBorderOutlined {
color: #f4b400 !important;
}
Surprised that no one has suggested a site-wide solution yet.
You can override the colors that are assigned for the "colors" option here https://material-ui.com/api/icon/#props
by adding an override to your theme (you'll have to define a custom theme if you aren't already) https://material-ui.com/customization/theming/#createmuitheme-options-args-theme
After defining a theme though, it's as simple as
const theme = createMuiTheme({
"overrides": {
MuiSvgIcon: {
colorPrimary: {
color: ["#625b5b", "!important"],
},
colorSecondary: {
color: ["#d5d7d8", "!important"],
},
},
...
});
Only correct solution that covers two tone (TwoTone) icons is to pass it htmColor property:
React.createElement(Icon, {htmlColor: "#00688b"})
To change color of your MUI Icons your have three ways: (Source)
//using a hex value
<BathroomIconOutlined style={{ color: "#ffee66" }} />
//using a standard css colour
<BathroomTwoToneIcon style={{ color: "blue" }} />
//import a material ui colour, and use that
import { purple } from "#mui/material/colors";
<BathroomIcon style={{ color: purple[500] }} />
Or use directly the MUI properties: (Source)
import SearchOutlined from '#mui/icons-material/SearchOutlined';
<SearchOutlined style={{ color: 'primary', fontSize: "small" }} />
<SearchOutlined style={{ color: 'secondary', fontSize: "medium" }} />
<SearchOutlined style={{ color: 'action', fontSize: "large" }} />
<SearchOutlined style={{ color: 'error', fontSize: 16 }} />
<SearchOutlined style={{ color: 'disabled', fontSize: 16 }} />
You can use SvgIcon, from the documentation:
The SvgIcon component takes an SVG path element as its child and
converts it to a React component that displays the path, and allows
the icon to be styled and respond to mouse events. SVG elements should
be scaled for a 24x24px viewport.
You must use the devTools to extract the path of the KeyboardArrowRightIcon icon:
Then use it with your custom color like this:
<SvgIcon
component={svgProps => {
return (
<svg {...svgProps}>
{React.cloneElement(svgProps.children[0], {
fill: myColorVariable
})}
</svg>
);
}}
>
<path d="M8.59 16.59L13.17 12 8.59 7.41 10 6l6 6-6 6-1.41-1.41z"></path>
</SvgIcon>
I had the same problem, me solution was:
import React from 'react';
import pure from 'recompose/pure';
import {SvgIcon} from '#material-ui/core';
let smile = (props) => (
<SvgIcon {...props}
component={props => {
return (
<svg {...props}>
{React.cloneElement(props.children[0], {
fill: "#4caf50"
})}
</svg>
);
}}
>
<path d="M256,32C132.281,32,32,132.281,32,256s100.281,224,224,224s224-100.281,224-224S379.719,32,256,32z M256,448
c-105.875,0-192-86.125-192-192S150.125,64,256,64s192,86.125,192,192S361.875,448,256,448z M160,192c0-26.5,14.313-48,32-48
s32,21.5,32,48c0,26.531-14.313,48-32,48S160,218.531,160,192z M288,192c0-26.5,14.313-48,32-48s32,21.5,32,48
c0,26.531-14.313,48-32,48S288,218.531,288,192z M384,288c-16.594,56.875-68.75,96-128,96c-59.266,0-111.406-39.125-128-96"></path>
</SvgIcon>
);
smile = pure(smile);
smile.displayName = 'smile';
smile.muiName = 'SvgIcon';
export default smile;
Solution that works the best for myself:
const EditableIcon = ({ icon, color, sx }: PropsWithChildren<EditableIconProps>) => {
const c = useIconStyles()
return React.cloneElement(icon, {
...(color && { color }),
...(sx && { sx }),
classes: {
colorPrimary: c.colorPrimary,
colorSecondary: c.colorSecondary,
colorAction: c.colorAction
}
})
}
If color is set, your classes would override default values.

Resources