Material-ui: [ButtonGroup] Support vertical option

Created on 15 Oct 2019  路  12Comments  路  Source: mui-org/material-ui


there is no vertical ButtonGroup in Material UI. how can I change horizontal ButtonGroup to vertical one? Do I make my own Buttons group together with display: 'block'?

ButtonGroup enhancement good first issue

All 12 comments

Hi,

I made a demo on codesandbox with a vertical button group.

Code: https://codesandbox.io/s/material-ui-vertical-button-group-o5dgf
Demo: https://o5dgf.csb.app/

Updated:
Code https://codesandbox.io/s/material-ui-vertical-button-group-bu52u
Demo: https://bu52u.csb.app

does this help? @sasanrasouli

I pushed up a PR which adds orientation to ButtonGroup, to see what folks think.

@adeelibr thank you, dude.

If this resolves your issue, can you kindly close this issue? :) @sasanrasouli

I have added the waiting for users upvotes tag. I'm not sure people are looking for such abstraction. So please upvote this issue if you are. We will prioritize our effort based on the number of upvotes.

@adeelibr, @slipmat Thanks for the help on this feature request.

What about something like this?

diff --git a/packages/material-ui/src/ButtonGroup/ButtonGroup.js b/packages/material-ui/src/ButtonGroup/ButtonGroup.js
index 9fb122ae6..7db68a33d 100644
--- a/packages/material-ui/src/ButtonGroup/ButtonGroup.js
+++ b/packages/material-ui/src/ButtonGroup/ButtonGroup.js
@@ -21,6 +21,10 @@ export const styles = theme => ({
   contained: {
     boxShadow: theme.shadows[2],
   },
+  /* Styles applied to the root element if `orientation="vertical"`. */
+  vertical: {
+    flexDirection: 'column',
+  },
   /* Styles applied to the root element if `fullWidth={true}`. */
   fullWidth: {
     width: '100%',
@@ -28,6 +32,9 @@ export const styles = theme => ({
   /* Styles applied to the children. */
   grouped: {
     minWidth: 40,
+  },
+  /* Styles applied to the children if `orientation="horizontal"`. */
+  groupedHorizontal: {
     '&:not(:first-child)': {
       borderTopLeftRadius: 0,
       borderBottomLeftRadius: 0,
@@ -37,14 +44,35 @@ export const styles = theme => ({
       borderBottomRightRadius: 0,
     },
   },
+  /* Styles applied to the children if `orientation="vertical"`. */
+  groupedVertical: {
+    '&:not(:first-child)': {
+      borderTopRightRadius: 0,
+      borderTopLeftRadius: 0,
+    },
+    '&:not(:last-child)': {
+      borderBottomRightRadius: 0,
+      borderBottomLeftRadius: 0,
+    },
+  },
   /* Styles applied to the children if `variant="text"`. */
-  groupedText: {
+  groupedText: {},
+  /* Styles applied to the children if `variant="text"` and `orientation="horizontal"`. */
+  groupedTextHorizontal: {
     '&:not(:last-child)': {
       borderRight: `1px solid ${
         theme.palette.type === 'light' ? 'rgba(0, 0, 0, 0.23)' : 'rgba(255, 255, 255, 0.23)'
       }`,
     },
   },
+  /* Styles applied to the children if `variant="text"` and `orientation="vertical"`. */
+  groupedTextVertical: {
+    '&:not(:last-child)': {
+      borderBottom: `1px solid ${
+        theme.palette.type === 'light' ? 'rgba(0, 0, 0, 0.23)' : 'rgba(255, 255, 255, 0.23)'
+      }`,
+    },
+  },
   /* Styles applied to the children if `variant="text"` and `color="primary"`. */
   groupedTextPrimary: {
     '&:not(:last-child)': {
@@ -58,7 +86,9 @@ export const styles = theme => ({
     },
   },
   /* Styles applied to the children if `variant="outlined"`. */
-  groupedOutlined: {
+  groupedOutlined: {},
+  /* Styles applied to the children if `variant="outlined"` and `orientation="horizontal"`. */
+  groupedOutlinedHorizontal: {
     '&:not(:first-child)': {
       marginLeft: -1,
     },
@@ -66,6 +96,15 @@ export const styles = theme => ({
       borderRightColor: 'transparent',
     },
   },
+  /* Styles applied to the children if `variant="outlined"` and `orientation="vertical"`. */
+  groupedOutlinedVertical: {
+    '&:not(:first-child)': {
+      marginTop: -1,
+    },
+    '&:not(:last-child)': {
+      borderBottomColor: 'transparent',
+    },
+  },
   /* Styles applied to the children if `variant="outlined"` and `color="primary"`. */
   groupedOutlinedPrimary: {
     '&:hover': {
@@ -81,6 +120,9 @@ export const styles = theme => ({
   /* Styles applied to the children if `variant="contained"`. */
   groupedContained: {
     boxShadow: 'none',
+  },
+  /* Styles applied to the children if `variant="contained"` and `orientation="horizontal"`. */
+  groupedContainedHorizontal: {
     '&:not(:last-child)': {
       borderRight: `1px solid ${theme.palette.grey[400]}`,
       '&$disabled': {
@@ -88,16 +130,25 @@ export const styles = theme => ({
       },
     },
   },
+  /* Styles applied to the children if `variant="contained"` and `orientation="vertical"`. */
+  groupedContainedVertical: {
+    '&:not(:last-child)': {
+      borderBottom: `1px solid ${theme.palette.grey[400]}`,
+      '&$disabled': {
+        borderBottom: `1px solid ${theme.palette.action.disabled}`,
+      },
+    },
+  },
   /* Styles applied to the children if `variant="contained"` and `color="primary"`. */
   groupedContainedPrimary: {
     '&:not(:last-child)': {
-      borderRight: `1px solid ${theme.palette.primary.dark}`,
+      borderColor: theme.palette.primary.dark,
     },
   },
   /* Styles applied to the children if `variant="contained"` and `color="secondary"`. */
   groupedContainedSecondary: {
     '&:not(:last-child)': {
-      borderRight: `1px solid ${theme.palette.secondary.dark}`,
+      borderColor: theme.palette.secondary.dark,
     },
   },
   /* Pseudo-class applied to child elements if `disabled={true}`. */
@@ -115,6 +166,7 @@ const ButtonGroup = React.forwardRef(function ButtonGroup(props, ref) {
     disableFocusRipple = false,
     disableRipple = false,
     fullWidth = false,
+    orientation = 'horizontal',
     size = 'medium',
     variant = 'outlined',
     ...other
@@ -122,7 +174,9 @@ const ButtonGroup = React.forwardRef(function ButtonGroup(props, ref) {

   const buttonClassName = clsx(
     classes.grouped,
+    classes[`grouped${capitalize(orientation)}`],
     classes[`grouped${capitalize(variant)}`],
+    classes[`grouped${capitalize(variant)}${capitalize(orientation)}`],
     classes[`grouped${capitalize(variant)}${color !== 'default' ? capitalize(color) : ''}`],
     {
       [classes.disabled]: disabled,
@@ -136,6 +190,7 @@ const ButtonGroup = React.forwardRef(function ButtonGroup(props, ref) {
         classes.root,
         {
           [classes.contained]: variant === 'contained',
+          [classes.vertical]: orientation === 'vertical',
           [classes.fullWidth]: fullWidth,
         },
         className,
@@ -214,6 +269,10 @@ ButtonGroup.propTypes = {
    * If `true`, the buttons will take up the full width of its container.
    */
   fullWidth: PropTypes.bool,
+  /**
+   * The group orientation.
+   */
+  orientation: PropTypes.oneOf(['horizontal', 'vertical']),
   /**
    * The size of the button.
    * `small` is equivalent to the dense button styling.

Capture d鈥檈虂cran 2019-12-04 a虁 00 12 10

@slipmat Do you want to resume your effort? :)

@oliviertassinari this issue is working by someone?

Not I'm aware of.

Sorry, I've been distracted on some other things.
Sandra, if you want to pick this up, your welcome, otherwise, I'm happy to resume.

@slipmat thank you in a few moments I create pull request of this :)

What would be the approach if you want to have icons that are aligned? Right now I have this:

          <ButtonGroup
            orientation="vertical"
            color="primary"
            aria-label="vertical outlined primary button group"
          >
            <Button
              variant="contained"
              color="secondary"
              type="button"
              endIcon={<Add />}
            >
              Add
            </Button>
            <Button color="primary" type="button" endIcon={<Remove />}>
              Remove
            </Button>
          </ButtonGroup>

image

Was this page helpful?
0 / 5 - 0 ratings