Material-UI: Toggle Accordion by simply clicking on the icon

I've set up an Accordion feature for my latest project, but I'm running into a small issue. Right now, the panel expands whenever any part of it is clicked, but I'd like it to only expand when the specific expand icon is clicked. Is there a way to customize this behavior?

Here's the code snippet:

import React from "react";
import ExpandMoreIcon from "@material-ui/icons/ExpandMore";
import Accordion from "@material-ui/core/Accordion";
import AccordionDetails from "@material-ui/core/AccordionDetails";
import Typography from "@material-ui/core/Typography";
import AccordionSummary from "@material-ui/core/AccordionSummary";

export default function App() {
return (
    <div style={{}}>
    <h4>How to create Accordion in ReactJS?</h4>
    <Accordion style={{ width: 400}}>
        <AccordionSummary 
         expandIcon={<ExpandMoreIcon />}
         aria-controls="panel1a-content"
        >   
          <div>Click to Expand</div>
        </AccordionSummary>
        <AccordionDetails>
        <Typography>Greetings of the day :)</Typography>
        </AccordionDetails>
    </Accordion>
    </div>
);
}

Answer №1

If you're looking to achieve a specific functionality that doesn't have a direct public API, there's a workaround using this handy CSS technique:

Method 1

<AccordionSummary
  sx={{
    pointerEvents: "none"
  }}
  expandIcon={
    <ExpandMoreIcon
      sx={{
        pointerEvents: "auto"
      }}
    />
  }
>

Method 2

const useStyles = makeStyles({
  summary: {
    pointerEvents: 'none',
  },
  icon: {
    pointerEvents: 'auto',
  },
});
<AccordionSummary
  className={classes.summary}
  expandIcon={<ExpandMoreIcon className={classes.icon} />}
>
  <Typography>Accordion 1</Typography>
</AccordionSummary>

Check out the Live Demo here

https://codesandbox.io/s/69358781-how-to-customize-accordion-behavior-from-material-ui-in-react-js-bqpr4?file=/demo.js

Answer №2

Indeed, this is the way to go

1- Establishing our custom state with a handler:

  const [expand, setExpand] = React.useState(false);
  const toggleAcordion = () => {
    setExpand((prev) => !prev);
  };

2- Integrating our state into the Accordion:

<Accordion expanded={expand} style={{ width: 400 }}>

3- Implementing onClick for the icon:

    <AccordionSummary
      expandIcon={<ExpandMoreIcon />}
      aria-controls="panel1a-content"
      IconButtonProps={{
        onClick: toggleAcordion
      }}
    >

Complete Code:

https://codesandbox.io/s/adoring-flower-0gy3k?file=/src/App.js:627-824

UPDATE: Clarification: The Material-UI Accordion comes with its own state (open or close) and click handler. In the approach above, we create our personal state and override the Material-UI Accordion state using the prop expanded, while adding an event listener onClick to the icon button through the IconButtonProps prop. Our event listener will open or close the Accordion by toggling our state.

NOTE: It's important to note that the code provided does not modify the cursor pointer styling.

Answer №3

To ensure proper functionality in version 5 and handle the mouse cursor:

1- Establish a custom state with a handler function:

const [isAccordionOpen, setAccordionOpen] = React.useState(false);

2- Integrate the created state into the Accordion component and enable toggling on click:

<Accordion expanded={isAccordionOpen}>
    <AccordionSummary
      expandIcon={
        <ExpandMoreIcon
          style={{ cursor: 'pointer' }}
          onClick={() => setAccordionOpen(!isAccordionOpen)} />
      }
      sx={{ cursor: 'unset !important' }}
    >

Answer №4

Unfortunately, none of the suggested solutions resolved my issue. I ended up using the e.stopPropagation() method within the onClick event of the icon to resolve the problem after invoking the toggle function.

Here's how I implemented it:

import React from "react";
import ExpandMoreIcon from "@material-ui/icons/ExpandMore";
import Accordion from "@material-ui/core/Accordion";
import AccordionDetails from "@material-ui/core/AccordionDetails";
import Typography from "@material-ui/core/Typography";
import AccordionSummary from "@material-ui/core/AccordionSummary";

export default function App() {
return (
    <div style={{}}>
    <h4>How to create Accordion in ReactJS?</h4>
    <Accordion style={{ width: 400}}>
        <AccordionSummary 
         expandIcon={<ExpandMoreIcon />}
         aria-controls="panel1a-content"
        >   
          <div ><img src='yourIcon' onClick={(e) => { toggleAccordion(); e.stopPropagation() }} /></div>
        </AccordionSummary>
        <AccordionDetails>
        <Typography>Greetings of the day :)</Typography>
        </AccordionDetails>
    </Accordion>
    </div>
);
}

Answer №5

One option to consider is toggling the expanded state in an Accordion component:

function Container(props) {
  const [isExpanded, setExpanded] = React.useState(false);
  const toggleAccordion = () => {
    setExpanded((prevExpanded) => !prevExpanded);
  };
  return (
    <React.Fragment>
      <Accordion expanded={isExpanded}>
        <AccordionSummary
          expandIcon={<ExpandMoreIcon onClick={toggleAccordion} />}
          aria-controls="panel1a-content"
          id="panel1a-header"
        >
          <Typography></Typography>
        </AccordionSummary>
        <AccordionDetails>
        </AccordionDetails>
      </Accordion>
    </React.Fragment>)
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>

Answer №6

Here is a solution I came up with for using the onChange property in Accordion (TypeScript version):

interface Props {
  information: {id: number, title: string, description: string}
}

const CustomAccordionComponent: React.FC<Props> = ({ information }) => {
  const [expanded, setExpanded] = useState<number | false>(false) 

  const handleExpansion = (id: number) => (_e: React.SyntheticEvent, isExpanded: boolean) => {
    setExpanded(isExpanded ? id : false)
  }

  return (
    <>
      <Accordion expanded={expanded === information.id} onChange={handleExpansion(information.id)}>
        <AccordionSummary expandIcon={<ExpandMoreIcon/>}>
          {information.title}
        </AccordionSummary>
        <AccordionDetails>
          {information.description}
        </AccordionDetails>
      </Accordion>
    </>
  )
}

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

The last-of-type pseudo-class in Material-UI (MUI)

I'm attempting to apply a margin of 100px to the last <NotificationContainer> component. Unfortunately, the code snippet I have included is not achieving this desired effect. My project is being developed using MUI5. const Container = styled(&ap ...

Effortless side-to-side and up-and-down scrolling

I recently launched a new website and I am looking to implement smooth horizontal and vertical scrolling. I want to have a menu on the right side that allows users to easily navigate to different sections. While I have found helpful codes and guides for ...

Adjust the size of a div while maintaining its aspect ratio based on the width and height of its parent element using CSS

After exploring various methods to create div aspect ratios using CSS, I had success with a demo. However, I encountered an issue with setting the height of my container when the width-to-height ratio is larger (#1 scenario). https://i.sstatic.net/VNdJ5.p ...

How to display an external link page in a popup using React

I'm having trouble displaying the Google page in my popup. When I try to load it, I get a message in the iframe saying 'www.google.com refused to connect' App.js import React from 'react'; import Popup from './components/Pop ...

A guide to properly placing objects in react-three-fiber

Currently, I have a cube mesh displayed on a canvas and my goal is to shift it to the left along the X-axis without altering its point of rotation. While attempting this task, I experimented with adding the argument position={[1,0,0]} to the mesh component ...

Leveraging local resources to create images with the help of @vercel/og and Next.js

Utilizing the latest @vercel/og library for generating meta-tag images has been quite intriguing. The official example showcases how to leverage images from an external source. The Quandary at Hand <img src={"https://res.cloudinary.com/iqfareez ...

Seeking assistance with creating an iPad application utilizing JQtouch - any t

I am attempting to create an iPad app using jQuery and jQTouch for the second time. I want to split the existing jQTouch theme designed for iPhone, which uses one window, into two separate windows optimized for the iPad. My goal is to have navigation on t ...

Receiving an eslint error while trying to integrate Stripe pricing table into a React web application

If you're looking to incorporate a Stripe documentation code snippet for adding a stripe-pricing-table element, here's what they suggest: import * as React from 'react'; // If you're using TypeScript, don't forget to include ...

using padding to vertically center an input element

Hey everyone, a few days ago I faced a challenge with centering an input element and someone suggested a solution which worked perfectly. You can view the solution on Stack Overflow. The CSS for centering the input element is quite simple and standard: h ...

Error: Unable to execute candidate.toLowerCase as a function

Encountering the following errors: `Uncaught TypeError: candidate.toLowerCase is not a function. I am utilizing the AutoComplete API within Material UI, however, when I search in the input field, it leads me to a blank page. https://i.sstatic.net/Yv3ZU.pn ...

When I zoom in, my h1 tags shift to the right

I am relatively new to this and I am puzzled as to why the text inside my h1 tag seems to shift to the right when I zoom in. Below is the CSS code: h1 { font-family: 'Raleway', sans-serif; border-bottom: 1px solid black; border-top: ...

React Admin: Choose from existing images or upload a new one

When working in an admin panel with images, there is usually the option to either select an existing image or upload a new one. I am curious how this functionality can be implemented using react admin. I have two specific questions: Is there a way to se ...

Is there a way to export from a module without including the src directory?

I currently have two modules in my project, where one is a dependency of the other. The first module, named base-module, has the following structure: / /src /Widget index.tsx package.json My goal is to import the Widget component ...

Is it feasible for nested div to remain unaffected by bleeding when the container is positioned relatively and has an overflow hidden

Is it possible to bleed a nested div even when the container is positioned relative with hidden overflow? In this case, giving the nested div a fixed position is not an option. Please check out this unique example: http://jsfiddle.net/s7nhw/11/. If you ...

Text within table cells on email appears to be shrinking on Windows Phone devices

Can anyone help me understand why Windows Phone reduces the font size when text is placed within a table cell that isn't at 100% width or nested? Below is a screenshot of a test email template I'm working on. When I sent it to a Windows Phone 8. ...

Issue with the placement of the bottom background when viewed in responsive mode

I'm encountering an issue with the placement of a bottom white image when I switch to responsive mode. It seems to not align at the bottom of the parent ul element as expected. If possible, could you provide assistance in addressing this issue? The i ...

What are the steps to design a curved gauge with a linear-gradient background?

Looking to create a fully responsive gauge using only CSS, ranging from 0-100% with a gradient color transition from green to red. After encountering issues with existing examples, I conducted tests and ultimately developed a solution that somewhat meets t ...

Navigating grid layouts with Material UI can be challenging, but by following a few key strategies

Although many people may have asked this question before, I couldn't find the answer, so I apologize. I am trying to figure out how to effectively use grid with Material-ui. Let me illustrate my issue with a picture: Picture illustrating my problem ...

React MUI5 component latency when changing disable prop conditionally

I've been experiencing issues with latency when trying to conditionally enable/disable a Material UI button. This problem arose after updating my materialUi and reactjs to the latest versions (React 18, MUI/Material: 5.10.10). I'm using a sample ...

Placing a list item at the beginning of an unordered list in EJS with MongoDB and Node.js using Express

What I've done: I already have knowledge on how to add an LI to UL, but it always goes to the bottom. What I'm trying to achieve: Add an LI to the top so that when my div.todos-wrapper (which has y-oveflow: hidden) hides overflow, the todos you a ...