Material-ui: [ListItemSecondaryAction] visibility on hover

Created on 13 Feb 2018  路  5Comments  路  Source: mui-org/material-ui

  • [x] I have searched the issues of this repository and believe that this is not a duplicate.

Expected Behavior

ListItemSecondaryAction should be able to be hidden by default, then visible on hover. This is a really common use case, so if possible, we should consider a clean way to make this (optional) behavior available behind a boolean property.

Current Behavior

When implemented with css sibling selectors and hovering over the secondary action, the icon blinks continuously. When hovered anywhere else on the ListItem, the blinking stops and works as expected.

blink2

Steps to Reproduce (for bugs)

Using css sibling selector (shown above): https://codesandbox.io/s/xo0mmyv2oo

Context

Secondary actions visible for larger lists (e.g. Google contacts list) can be overwhelming. Hiding icons until hovered is a common way to declutter user interfaces.

Your Environment

| Tech | Version |
|--------------|---------|
| Material-UI | 1.0.0-beta.33 |
| React | 16.2.0 |
| browser | Chrome |

Any guidance @oliviertassinari @kof as to what the root cause of blinking?

List question

Most helpful comment

import React from "react";
import PropTypes from "prop-types";
import { withStyles } from "material-ui/styles";
import List, {
  ListItem,
  ListItemSecondaryAction,
  ListItemText
} from "material-ui/List";
import Checkbox from "material-ui/Checkbox";
import IconButton from "material-ui/IconButton";
import CommentIcon from "material-ui-icons/Comment";

const styles = theme => ({
  root: {
    width: "100%",
    maxWidth: 360,
    backgroundColor: theme.palette.background.paper
  },
  listItemSecondaryAction: {
    visibility: "hidden"
  },
  listItem: {
    border: "1px solid blue",
-   "&:hover ~ $listItemSecondaryAction": {
+   "&:hover $listItemSecondaryAction": {
      border: "1px solid green",
      visibility: "inherit"
    }
  }
});

class CheckboxList extends React.Component {
  state = {
    checked: [0]
  };

  handleToggle = value => () => {
    const { checked } = this.state;
    const currentIndex = checked.indexOf(value);
    const newChecked = [...checked];

    if (currentIndex === -1) {
      newChecked.push(value);
    } else {
      newChecked.splice(currentIndex, 1);
    }

    this.setState({
      checked: newChecked
    });
  };

  render() {
    const { classes } = this.props;

    return (
      <div className={classes.root}>
        <List>
          {[0, 1, 2, 3].map(value => (
            <ListItem
              key={value}
              dense
              button
              onClick={this.handleToggle(value)}
-             className={classes.listItem}
+             classes={{
+               container: classes.listItem
+             }}
            >
              <Checkbox
                checked={this.state.checked.indexOf(value) !== -1}
                tabIndex={-1}
                disableRipple
              />
              <ListItemText primary={`Line item ${value + 1}`} />
              <ListItemSecondaryAction
                className={classes.listItemSecondaryAction}
              >
                <IconButton aria-label="Comments">
                  <CommentIcon />
                </IconButton>
              </ListItemSecondaryAction>
            </ListItem>
          ))}
        </List>
      </div>
    );
  }
}

CheckboxList.propTypes = {
  classes: PropTypes.object.isRequired
};

export default withStyles(styles)(CheckboxList);

https://codesandbox.io/s/l3n2nwpzq7

All 5 comments

Interesting - mouseover/mouseout causes the same thing.
https://codesandbox.io/s/21kw46kvj0

This looks like an event problem with ButtonBase?

@rosskevin It sounds like the expected behavior. Let me post the correct approach.

import React from "react";
import PropTypes from "prop-types";
import { withStyles } from "material-ui/styles";
import List, {
  ListItem,
  ListItemSecondaryAction,
  ListItemText
} from "material-ui/List";
import Checkbox from "material-ui/Checkbox";
import IconButton from "material-ui/IconButton";
import CommentIcon from "material-ui-icons/Comment";

const styles = theme => ({
  root: {
    width: "100%",
    maxWidth: 360,
    backgroundColor: theme.palette.background.paper
  },
  listItemSecondaryAction: {
    visibility: "hidden"
  },
  listItem: {
    border: "1px solid blue",
-   "&:hover ~ $listItemSecondaryAction": {
+   "&:hover $listItemSecondaryAction": {
      border: "1px solid green",
      visibility: "inherit"
    }
  }
});

class CheckboxList extends React.Component {
  state = {
    checked: [0]
  };

  handleToggle = value => () => {
    const { checked } = this.state;
    const currentIndex = checked.indexOf(value);
    const newChecked = [...checked];

    if (currentIndex === -1) {
      newChecked.push(value);
    } else {
      newChecked.splice(currentIndex, 1);
    }

    this.setState({
      checked: newChecked
    });
  };

  render() {
    const { classes } = this.props;

    return (
      <div className={classes.root}>
        <List>
          {[0, 1, 2, 3].map(value => (
            <ListItem
              key={value}
              dense
              button
              onClick={this.handleToggle(value)}
-             className={classes.listItem}
+             classes={{
+               container: classes.listItem
+             }}
            >
              <Checkbox
                checked={this.state.checked.indexOf(value) !== -1}
                tabIndex={-1}
                disableRipple
              />
              <ListItemText primary={`Line item ${value + 1}`} />
              <ListItemSecondaryAction
                className={classes.listItemSecondaryAction}
              >
                <IconButton aria-label="Comments">
                  <CommentIcon />
                </IconButton>
              </ListItemSecondaryAction>
            </ListItem>
          ))}
        </List>
      </div>
    );
  }
}

CheckboxList.propTypes = {
  classes: PropTypes.object.isRequired
};

export default withStyles(styles)(CheckboxList);

https://codesandbox.io/s/l3n2nwpzq7

@rosskevin Oops. I haven't saved the codesandbox. Done

Awesome thanks @oliviertassinari. I couldn't get your url to load your changes so I forked it in case anyone else runs across it - https://codesandbox.io/s/649v7kozm3

Thanks again for taking a look.

Was this page helpful?
0 / 5 - 0 ratings