I'm keeping a menu list in my database, and with it I also keep the icons. The challenge is that the Icons are MUI icons and being saved as the React node element.
For example:
<HomeIcon fontSize="small" />
When I'm rendering the menu list, everything looks great, BESIDE the icons - as it render them as text and not as React elements.
I tried so many options to render them as React, but couldn't find the right solution.
The last thing I used is Parse ('html-react-parser'), but with no success as it saves the elements in lower cases.
This is the parsing code:
const icon = (item.icon ? parse(item.icon, {lowerCaseTags: false}) : "");
But then I'm receiving the following error:
Warning: The tag <homeicon> is unrecognized in this browser. If you meant to render a React component, start its name with an uppercase letter.
at homeicon
at span
That's the React node that I'm rendering:
<DashboardSidebarItem
active={partialMatch}
chip={item.chip}
depth={depth}
icon={icon}
info={item.info}
key={key}
open={partialMatch}
path={item.path}
title={item.title}
>
{renderNavItems({
depth: depth + 1,
items: item.children,
path
})}
</DashboardSidebarItem>
And that's DashboardSidebarItem element:
export const DashboardSidebarItem = (props) => {
const {
active,
children,
chip,
depth,
icon,
info,
open: openProp,
path,
title,
...other
} = props;
const [open, setOpen] = useState(openProp);
const handleToggle = () => {
setOpen((prevOpen) => !prevOpen);
};
let paddingLeft = 24;
if (depth > 0) {
paddingLeft = 32 + 8 * depth;
}
// I NEED TO CONVERT IT TO REACT NATIVE
// Branch
if (children) {
return (
<ListItem
disableGutters
sx={{
display: 'block',
mb: 0.5,
py: 0,
px: 2
}}
{...other}>
<Button
endIcon={!open
? <ChevronRightIcon fontSize="small" />
: <ChevronDownIcon fontSize="small" />}
disableRipple
onClick={handleToggle}
startIcon={icon}
sx={{
color: active ? 'secondary.main' : 'neutral.300',
justifyContent: 'flex-start',
pl: `${paddingLeft}px`,
pr: 3,
textAlign: 'left',
textTransform: 'none',
width: '100%',
'&:hover': {
backgroundColor: 'rgba(255,255,255, 0.08)'
},
'& .MuiButton-startIcon': {
color: active ? 'secondary.main' : 'neutral.400'
},
'& .MuiButton-endIcon': {
color: 'neutral.400'
}
}}
>
<Box sx={{ flexGrow: 1 }}>
{title}
</Box>
{info}
</Button>
<Collapse
in={open}
sx={{ mt: 0.5 }}
>
{children}
</Collapse>
</ListItem>
);
}
// Leaf
return (
<ListItem disableGutters sx={{display: 'flex', mb: 0.5, py: 0, px: 2 }}>
<NextLink href={path} passHref >
<Button
component="a"
startIcon={icon}
endIcon={chip}
disableRipple
sx={{
backgroundColor: active && 'rgba(255,255,255, 0.08)',
borderRadius: 1,
color: active ? 'secondary.main' : 'neutral.300',
fontWeight: active && 'fontWeightBold',
justifyContent: 'flex-start',
pl: `${paddingLeft}px`,
pr: 3,
textAlign: 'left',
textTransform: 'none',
width: '100%',
'& .MuiButton-startIcon': {
color: active ? 'secondary.main' : 'neutral.400'
},
'&:hover': {
backgroundColor: 'rgba(255,255,255, 0.08)'
}
}}
>
<Box sx={{ flexGrow: 1 }}>
{title}
</Box>
{info}
</Button>
</NextLink>
</ListItem>
);
};
I wouldn't recommend you to do any kind of parsing due security vulnerabilities like XSS.
I could be wrong but if you are loading icons from the database like:
Remember that user components must be capitalized, btw, you also need to import the icons before using them, so, a better approach would be:
Navigate to the following section for more details: Icon (Font icons)
This is a basic example of the whole implementation:
In this way you could also store props like color, sx, fontSize, etc, from the official material-ui documentation and store them in the database to make the component more escalable.