How can I programmatically add/ remove the material-UI classes that I defined in makeStyles()
Here's my code:
import React from 'react';
import { DropboxIcon, GoogleDriveIcon, BoxIcon } from '../ponents/icons';
import { makeStyles } from '@material-ui/core/styles';
const useStyles = makeStyles(theme => ({
input: {
display: 'none'
},
label: {
display: 'inline-flex',
marginRight: theme.spacing(2),
marginLeft: theme.spacing(2),
justifyCOntent: 'space-between',
padding: theme.spacing(1, 1.5)
},
iconName: {
marginLeft: theme.spacing(1)
},
iconsFormWrapper: {
marginTop: theme.spacing(2)
},
selectedService: {
backgroundColor: theme.palette.primary.dark,
borderRadius: theme.spacing(1),
color: '#ffffff',
'& svg, img': {
fill: '#ffffff!important',
filter: 'brightness(0) invert(1)'
}
}
}));
const selectServiceHandle = (e) => {
const optionName = document.getElementsByName("signup-service");
optionName.classList.remove("selectedService")
document.querySelectorAll(`input[value=${e.target.value}]`).classList.add("selectedService")
}
const SignupRadioIcons = () => {
const classes = useStyles();
return (
<div className={classes.iconsFormWrapper}>
<form>
<label className={`${classes.label} ${classes.selectedService}`}>
<DropboxIcon/> <span className={classes.iconName}>Dropbox</span>
<input type="radio" onChange={(e)=>selectServiceHandle(e)} name="signup-service" value="dropbox" className={classes.input} />
</label>
<label className={classes.label}>
<GoogleDriveIcon/> <span className={classes.iconName}>Google Drive</span>
<input type="radio" onChange={(e)=>selectServiceHandle(e)} name="signup-service" value="drive" className={classes.input} />
</label>
<label className={classes.label}>
<BoxIcon/> <span className={classes.iconName}>Box</span>
<input type="radio" onChange={(e)=>selectServiceHandle(e)} name="signup-service" value="box" className={classes.input} />
</label>
</form>
</div>
)
}
export default SignupRadioIcons;
In my code, I defined a class called selectedService
in my makeStyles()
But I want to add/remove this class on every change event, Whenever a user click any input I want to remove this class from all other inputs and add it to the one where the user clicked. But this code is not working because the actual classes that is generated by material UI look like makeStyles-selectedService-224
and the postfix number keeps on changing on every refresh.
How can I programmatically add/ remove the material-UI classes that I defined in makeStyles()
Here's my code:
import React from 'react';
import { DropboxIcon, GoogleDriveIcon, BoxIcon } from '../ponents/icons';
import { makeStyles } from '@material-ui/core/styles';
const useStyles = makeStyles(theme => ({
input: {
display: 'none'
},
label: {
display: 'inline-flex',
marginRight: theme.spacing(2),
marginLeft: theme.spacing(2),
justifyCOntent: 'space-between',
padding: theme.spacing(1, 1.5)
},
iconName: {
marginLeft: theme.spacing(1)
},
iconsFormWrapper: {
marginTop: theme.spacing(2)
},
selectedService: {
backgroundColor: theme.palette.primary.dark,
borderRadius: theme.spacing(1),
color: '#ffffff',
'& svg, img': {
fill: '#ffffff!important',
filter: 'brightness(0) invert(1)'
}
}
}));
const selectServiceHandle = (e) => {
const optionName = document.getElementsByName("signup-service");
optionName.classList.remove("selectedService")
document.querySelectorAll(`input[value=${e.target.value}]`).classList.add("selectedService")
}
const SignupRadioIcons = () => {
const classes = useStyles();
return (
<div className={classes.iconsFormWrapper}>
<form>
<label className={`${classes.label} ${classes.selectedService}`}>
<DropboxIcon/> <span className={classes.iconName}>Dropbox</span>
<input type="radio" onChange={(e)=>selectServiceHandle(e)} name="signup-service" value="dropbox" className={classes.input} />
</label>
<label className={classes.label}>
<GoogleDriveIcon/> <span className={classes.iconName}>Google Drive</span>
<input type="radio" onChange={(e)=>selectServiceHandle(e)} name="signup-service" value="drive" className={classes.input} />
</label>
<label className={classes.label}>
<BoxIcon/> <span className={classes.iconName}>Box</span>
<input type="radio" onChange={(e)=>selectServiceHandle(e)} name="signup-service" value="box" className={classes.input} />
</label>
</form>
</div>
)
}
export default SignupRadioIcons;
In my code, I defined a class called selectedService
in my makeStyles()
But I want to add/remove this class on every change event, Whenever a user click any input I want to remove this class from all other inputs and add it to the one where the user clicked. But this code is not working because the actual classes that is generated by material UI look like makeStyles-selectedService-224
and the postfix number keeps on changing on every refresh.
4 Answers
Reset to default 3You can set state to the currently selected radio's value, then use a conditional statement to check if the selected value equals the currently selected state in order to apply css
.
I would remend converting your radio's into JSON objects, then looping through them - this makes things a lot easier.
I have provided an example of how to handle this without using a loop, as well as with using a loop in the SandBox below.
Example Code Using JSON & Looping:
import React, { useState } from "react";
import { makeStyles } from "@material-ui/core/styles";
import Dropbox from "./Dropbox.js";
import Box from "./Box.js";
import Drive from "./Drive.js";
const base = {
fontSize: "20px"
};
const useStyles = makeStyles(theme => ({
base: {
...base
},
selected: {
...base,
fontSize: "40px",
backgroundColor: "yellow",
textDecorationLine: "underline"
}
}));
const radioObjects = [
{
label: Dropbox,
value: "dropbox"
},
{
label: Drive,
value: "drive"
},
{
label: Box,
value: "box"
}
];
export default function WithLoop() {
const classes = useStyles();
const [currentlyChecked, setCurrentlyChecked] = useState();
function handleChange(event) {
setCurrentlyChecked(event.target.value);
// do work
}
return (
<div>
<form>
{radioObjects.map(RadioItem => {
return (
<div key={RadioItem.value}>
<label
className={
currentlyChecked === RadioItem.value
? classes.selected
: classes.base
}
>
<RadioItem.label />
<input
value={RadioItem.value}
onChange={handleChange}
type="radio"
name="signup-service"
/>
</label>
</div>
);
})}
</form>
</div>
);
}
Given you are using React, I'd suggest you use local state to determine when to apply the class
import React, { useState } from 'react';
const storageProviders = {
Dropbox: 1,
GoogleDrive: 2,
Box: 3
};
...
const SignupRadioIcons = () => {
const classes = useStyles();
const [focusedInput, setFocusedInput] = useState(storageProviders.Dropbox);
return (
<div className={classes.iconsFormWrapper}>
<form>
<label className={`${classes.label} ${focusedInput === storageProviders.Dropbox ? classes.selectedService : ''}`}>
<DropboxIcon/> <span className={classes.iconName}>Dropbox</span>
<input type="radio" onChange={() => setFocusedInput(storageProviders.Dropbox)} name="signup-service" value="dropbox" className={classes.input} />
</label>
<label className={`${classes.label} ${focusedInput === storageProviders.GoogleDrive ? classes.selectedService : ''}`}>
<GoogleDriveIcon/> <span className={classes.iconName}>Google Drive</span>
<input type="radio" onChange={() => setFocusedInput(storageProviders.GoogleDrive)} name="signup-service" value="drive" className={classes.input} />
</label>
<label className={`${classes.label} ${focusedInput === storageProviders.Box ? classes.selectedService : ''}`}>
<BoxIcon/> <span className={classes.iconName}>Box</span>
<input type="radio" onChange={() => setFocusedInput(storageProviders.Box)} name="signup-service" value="box" className={classes.input} />
</label>
</form>
</div>
)
}
There's a mon pattern there that you could probably move into a reusable ponent but you get the jist of it.
This code will work if react version is more than 16
import React, { useState } from 'react';
const SignupRadioIcons = () => {
const classes = useStyles();
const [selectedService, setSelectedService]= useState('dropbox');
return (
<div className={classes.iconsFormWrapper}>
<form>
<label className={`${classes.label} ${selectedService === 'dropbox' ? classes.selectedService : undefined}`}>
<DropboxIcon/> <span className={classes.iconName}>Dropbox</span>
<input type="radio" onChange={(e)=> setSelectedService('dropbox')} name="signup-service" value="dropbox" className={classes.input} />
</label>
<label className={`${classes.label} ${selectedService === 'googleDrive' ? classes.selectedService : undefined}`}>
<GoogleDriveIcon/> <span className={classes.iconName}>Google Drive</span>
<input type="radio" onChange={(e)=> setSelectedService('googleDrive')} name="signup-service" value="drive" className={classes.input} />
</label>
<label className={`${classes.label} ${selectedService === 'box' ? classes.selectedService : undefined}`}>
<BoxIcon/> <span className={classes.iconName}>Box</span>
<input type="radio" onChange={(e)=> setSelectedService('box')} name="signup-service" value="box" className={classes.input} />
</label>
</form>
</div>
)
}
You can use ClassNameGenerator
To rename ponent class name:
import { unstable_ClassNameGenerator as ClassNameGenerator } from '@mui/material/className';
ClassNameGenerator.configure((ponentName) => ponentName.replace('Mui', ''));
For example:
ClassNameGenerator.configure((MuiSelect) => MuiSelect.replace('Mui', ''));
Where "the" Mui is the prefix of your ponent (all the Material ponents use the same prefix).
Have a look at the documentation