Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Button components inside ButtonGroup

I'm using React 16.9.0 and Material-UI 4.4.2 and I'm having the following issue.

I want to render a ButtonGroup with Button elements inside it but these buttons come from other custom components which return a Button render with a Modal view linked to the button. Thing is, I can't make them look like a ButtonGroup with the same style since it seems like the Button elements only take the "grouping" styling but not the "visual" styling.

Example code to reproduce behaviour:

<ButtonGroup variant="outlined">
    <AModal/>
    <BModal/>
    <CModal/>
</ButtonGroup>

Output

As you can see, the render output does not look as expected. Bare in mind that I'm defining the buttons with the outlined variant since if not they just render as Text Buttons.

Any help is much appreciated

Adding AModal as requested:

import React from 'react';
import { makeStyles } from '@material-ui/core/styles';
import { Button } from '@material-ui/core';
import Modal from '@material-ui/core/Modal';
import Backdrop from '@material-ui/core/Backdrop';
import Fade from '@material-ui/core/Fade';
import InnerModalComponent from './InnerModalComponent';

const useStyles = makeStyles((theme) => ({
    modal: {
        display: 'flex',
        alignItems: 'center',
        justifyContent: 'center',
    },
    paper: {
        backgroundColor: theme.palette.background.paper,
        border: '2px solid #000',
        boxShadow: theme.shadows[5],
        padding: theme.spacing(2, 4, 3),
    },
}));

export default function AModal() {
    const classes = useStyles();
    const [open, setOpen] = React.useState(false);

    function handleOpen() {
        setOpen(true);
    }

    function handleClose() {
        setOpen(false);
    }

    return (
        <div>
            <Button variant="contained" onClick={handleOpen}> A </Button>
            <Modal
                aria-labelledby="transition-modal-title"
                aria-describedby="transition-modal-description"
                className={classes.modal}
                open={open}
                onClose={handleClose}
                closeAfterTransition
                BackdropComponent={Backdrop}
                BackdropProps={{ timeout: 500 }}
            >
                <Fade in={open}>
                    <div className={classes.paper}>
                        <div
                            style={{
                                display: 'flex',
                                flexDirection: 'row',
                                alignItems: 'stretch',
                                justifyContent: 'center',
                            }}
                        >
                            <InnerModalComponent/>
                        </div>
                        <Button variant="contained" color="secondary" style={{ marginTop: '10px' }}> Button inside Modal</Button>
                    </div>
                </Fade>
            </Modal>
        </div>
    );
}
like image 538
Juani Condina Avatar asked Sep 16 '19 17:09

Juani Condina


1 Answers

There are two main issues:

  1. You are adding a div around each of your buttons. This will interfere a little with the styling. Change this to a fragment (e.g. <> or <React.Fragment>) instead.

  2. The way that ButtonGroup works is by cloning the child Button elements and adding props to control the styling. When you introduce a custom component in between, you need to pass through to the Button any props not used by your custom component.

Here is a working example:

import React from "react";
import ReactDOM from "react-dom";

import ButtonGroup from "@material-ui/core/ButtonGroup";
import Button from "@material-ui/core/Button";
import Modal from "@material-ui/core/Modal";

const AModal = props => {
  return (
    <>
      <Button {...props}>A</Button>
      <Modal open={false}>
        <div>Hello Modal</div>
      </Modal>
    </>
  );
};
const OtherModal = ({ buttonText, ...other }) => {
  return (
    <>
      <Button {...other}>{buttonText}</Button>
      <Modal open={false}>
        <div>Hello Modal</div>
      </Modal>
    </>
  );
};
// I don't recommend this approach due to maintainability issues,
// but if you have a lint rule that disallows prop spreading, this is a workaround.
const AvoidPropSpread = ({
  className,
  disabled,
  color,
  disableFocusRipple,
  disableRipple,
  fullWidth,
  size,
  variant
}) => {
  return (
    <>
      <Button
        className={className}
        disabled={disabled}
        color={color}
        disableFocusRipple={disableFocusRipple}
        disableRipple={disableRipple}
        fullWidth={fullWidth}
        size={size}
        variant={variant}
      >
        C
      </Button>
      <Modal open={false}>
        <div>Hello Modal</div>
      </Modal>
    </>
  );
};
function App() {
  return (
    <ButtonGroup>
      <AModal />
      <OtherModal buttonText="B" />
      <AvoidPropSpread />
    </ButtonGroup>
  );
}

const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);

Edit ButtonGroup with Modals

like image 99
Ryan Cogswell Avatar answered Nov 09 '22 04:11

Ryan Cogswell