Material-ui: [Menu] Support grouping / categories

Created on 27 Dec 2015  路  14Comments  路  Source: mui-org/material-ui

Please add feature like this
image

Menu Select enhancement important

Most helpful comment

As a walkaround, you can use the following snippet to get appearance pretty closely matching what the native one would be. One disadvantage to this approach is definitely accessibility though. Anyway, this works for me and might be useful to somebody else, so I'm posting it.

const Example = ({ classes }) => (
    <Select value={0}>
        <MenuItem disabled className={classes.group}>
            Nonsense
        </MenuItem>
        <MenuItem value={0} className={classes.item}>
            something
        </MenuItem>
        <MenuItem value={1} className={classes.item}>
            another
        </MenuItem>
        <MenuItem disabled className={classes.group}>
            Acronyms
        </MenuItem>
        <MenuItem value={2} className={classes.item}>
            lol
        </MenuItem>
        <MenuItem value={3} className={classes.item}>
            rofl
        </MenuItem>
    </Select>
);

const styles = (theme) => ({
    item: {
        paddingLeft: 3 * theme.spacing.unit,
    },
    group: {
        fontWeight: theme.typography.fontWeightMedium,
        opacity: 1,
    },
});

export default withStyles(styles)(Example);

image

All 14 comments

Thanks :+1: :+1:

@oliviertassinari Can I try this one?.. If yes, Can I create seperate component or alter the existing select component to achieve this??.

Okay. Will look into those issues.

hey, any updates on this feature request?

Do we have any progress on this? are the more important issues that oliviertassinari listed still being worked on?

I am very interested in this as well! It would be fantastic to have this be a possibility without using a native select styling.

+1 on the waiting list for this one...

I've made a component that implements this, I can post a repo with this on the weekend.
It's in ES6, and I don't think it's mergable, put it's something...

As a walkaround, you can use the following snippet to get appearance pretty closely matching what the native one would be. One disadvantage to this approach is definitely accessibility though. Anyway, this works for me and might be useful to somebody else, so I'm posting it.

const Example = ({ classes }) => (
    <Select value={0}>
        <MenuItem disabled className={classes.group}>
            Nonsense
        </MenuItem>
        <MenuItem value={0} className={classes.item}>
            something
        </MenuItem>
        <MenuItem value={1} className={classes.item}>
            another
        </MenuItem>
        <MenuItem disabled className={classes.group}>
            Acronyms
        </MenuItem>
        <MenuItem value={2} className={classes.item}>
            lol
        </MenuItem>
        <MenuItem value={3} className={classes.item}>
            rofl
        </MenuItem>
    </Select>
);

const styles = (theme) => ({
    item: {
        paddingLeft: 3 * theme.spacing.unit,
    },
    group: {
        fontWeight: theme.typography.fontWeightMedium,
        opacity: 1,
    },
});

export default withStyles(styles)(Example);

image

I get unexpected strange behaviour when doing that where I cannot debug or modify the style of the disabled groups properly, sometimes they will show gray, and they cannot be debugged on why they show as gray.

Added some CSS rules and now it seems to be perfect:

  MenuItem: {
    paddingLeft: 3 * theme.spacing.unit
  },
  MenuGroup: {
    fontWeight: theme.typography.fontWeightMedium,
    opacity: 1,
    cursor: "default",
    "&:hover": {
      backgroundColor: "transparent !important"
    }
  }

For the interested, I create a DRY way to the @jankalfus amazing solution:

import React from 'react';
import MenuItem from "@material-ui/core/MenuItem";
import withStyles from "@material-ui/core/styles/withStyles";

const styles = theme => ({
  item: {
    paddingLeft: theme.spacing(3),
  },
  group: {
    fontWeight: theme.typography.fontWeightMedium,
    opacity: 1,
  },
});

const customMenuItem = ({ classes, children, groupHead, groupItem, ...props}) => {
  let disabled = false;
  let className = [props.className];

  if (groupHead) {
    disabled = true;
    className.push(classes.group);
  }

  if (groupItem) {
    className.push(classes.item);
  }

  return <MenuItem
    disabled={disabled}
    className={className.join(' ')}
    {...props}>{children}</MenuItem>;
};

const AppMenuItem = withStyles(styles)(customMenuItem);

export default AppMenuItem;

And can use this way:

<AppMenuItem value='Foo'>Foo</AppMenuItem> // Just like MUI MenuItem
<AppMenuItem groupHead>Bar</AppMenuItem> // As a head
<AppMenuItem groupItem value={Baz}>Baz</AppMenuItem> // As an item

Actually, I'd recommend just creating two styled components:

const MenuGroupItem = withStyles({
    root: {
        paddingLeft: theme.spacing(3),
    },
})(MenuItem);

const MenuGroupNameBase = (props) => <MenuItem {...props} disabled />;

const MenuGroupName = withStyles({
    root: {
        fontWeight: theme.typography.fontWeightMedium,
        opacity: "1 !important",
    },
});

and use them like this:

<MenuGroupName>Some name</MenuGroupName>
<MenuGroupItem value="item1">Item 1</MenuGroupItem>
<MenuGroupItem value="item2">Item 2</MenuGroupItem>

It's more simple, without any logic. I haven't tested the code above, but you get the idea :)

Was this page helpful?
0 / 5 - 0 ratings