My goal is when I click on a ListItem, it should change the background-color
and text: "line-through"
. And then, if I click again, these changes should be canceled.
But it happens very strangely for me. I just can't understand why ListItem
changes background-color
only after I click to any place of the window? And why text into ListItem becomes crossed out only after I move pointer beyond the element
const styles = () => ({
listItem: {
borderRadius: "1em"
},
listItemDone: {
borderRadius: "1em",
backgroundColor: "#F6F6E8",
textDecoration: "line-through"
},
iconButton: {
padding: 5
},
important: {
color: "#00ACE9",
fontWeight: "bold"
}
});
class TodoListItem extends Component {
state = {
done: false
};
onClickItem = () => {
this.setState({
done: !this.state.done
});
};
render() {
const { label, important = false, classes } = this.props;
const { done } = this.state;
return (
<ListItem
onClick={this.onClickItem}
className={done ? classes.listItemDone : classes.listItem}
button
divider
>
<ListItemText
primary={label}
classes={{ primary: important ? classes.important : "" }}
/>
</ListItem>
);
}
}
Whenever you are trying to override Material-UI styles and it isn't working like you would expect, the best resource is the source code. Here is the URL for the ListItem
source code: https://github.com/mui-org/material-ui/blob/master/packages/material-ui/src/ListItem/ListItem.js. For the most part, you only need to look at the styles
variable near the top of the source file.
Below I've copied all of the portions of the styles
variable that deal with backgroundColor
and textDecoration
:
export const styles = theme => ({
/* Styles applied to the (normally root) `component` element. May be wrapped by a `container`. */
root: {
textDecoration: 'none',
'&$selected, &$selected:hover, &$selected:focus': {
backgroundColor: theme.palette.action.selected,
},
},
/* Styles applied to the inner `component` element if `button={true}`. */
button: {
transition: theme.transitions.create('background-color', {
duration: theme.transitions.duration.shortest,
}),
'&:hover': {
textDecoration: 'none',
backgroundColor: theme.palette.action.hover,
// Reset on touch devices, it doesn't add specificity
'@media (hover: none)': {
backgroundColor: 'transparent',
},
},
'&:focus': {
backgroundColor: theme.palette.action.hover,
},
},
/* Styles applied to the root element if `selected={true}`. */
selected: {},
});
The main styles causing difficulty are the button
hover and focus styles. In order to override these successfully without resorting to "!important", you need to have the appropriate CSS specificity.
The following seems to do the trick:
listItemDone: {
borderRadius: "1em",
"&,&:focus,&:hover": {
backgroundColor: "#F6F6E8",
textDecoration: "line-through"
}
},
However, the above prevents there from being any hover effect on "done" items, so you may instead want to do something more like:
listItemDone: {
borderRadius: "1em",
"&,&:focus": {
backgroundColor: "#F6F6E8",
textDecoration: "line-through"
},
"&:hover": {
textDecoration: "line-through"
}
},
This allows the hover background color of done items to still be theme.palette.action.hover
. If you want the hover color to be different for done items, you can specify it explicitly along with the textDecoration.
There is one other detail to take care of. If you click a list item to put it in a "done" state and then click it again, it will not be in the "done" state anymore but it will have the button
focus styles applied. In order to remove that focus styling, you also need the following:
listItem: {
borderRadius: "1em",
"&,&:focus": {
backgroundColor: theme.palette.background.paper // or whatever color you want this to be
}
},
Here is my modified version of your sandbox:
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With