Is there a way to trigger Material-UI SpeedDialAction onClick events only when the SpeedDial is open and clicked, not when it is hovered over?

After making a modification to material-ui's <SpeedDial> component by removing the onMouseEnter={handleOpen} prop, I noticed that the onClick event within the <SpeedDialAction> component no longer triggers when clicking on a menu item. It seems like there might be a key concept that I am overlooking.

  return (
    <SpeedDial
      ariaLabel="Add"
      className={classes.root}
      icon={<SpeedDialIcon />}
      onClick={handleClick}
      onClose={handleClose}
      onBlur={handleClose}
      // onMouseEnter={handleOpen}
      // onMouseLeave={handleClose}
      open={open}
      direction={mobile ? 'up' : 'down'}
    >
      {actions.map(action => (
        <SpeedDialAction
          key={action.name}
          icon={action.icon}
          tooltipTitle={action.name}
          tooltipOpen
          classes={{ staticTooltipLabel: classes.staticTooltipLabel }}
          onClick={e => {
            e.preventDefault();
            alert('x');
          }}
        />
      ))}
    </SpeedDial>
  );

Answer №1

When using the preventDefault function, it does not stop the click event from bubbling up to the parent element (which seems to be your goal).

To achieve this, you should utilize the stopPropagation method instead:

<SpeedDial
  ariaLabel="Add"
  className={classes.SpeedDial}
  icon={<SpeedDialIcon />}
  onClick={handleClick}
  open={open}
>
  {actions.map(action => (
    <SpeedDialAction
      key={action.name}
      icon={action.icon}
      tooltipTitle={action.name}
      tooltipOpen
      onClick={e => {
        e.stopPropagation();
        alert("x");
      }}
    />
  ))}
</SpeedDial>

For a demonstration, you can view the example here: https://codesandbox.io/s/speeddial-open-on-click-rleg5?file=/demo.js

Answer №2

I opt to assign the onclick handler to the icon instead

  • (more precisely, the parent <button> (the blue circle) of the icon
    otherwise, you have to click at the exact position of icon, instead of the blue circle

  • -- but this feels hacky...
    -- wish MaterialUi provides better Api for SpeedDial for this...)

code:

  • @watch for this part:

            <SpeedDialIcon
              ref={React.useCallback((elt: HTMLElement | null | any) => {
                if (elt instanceof HTMLElement) {
                  if (elt.parentElement instanceof HTMLButtonElement) {
                    elt.parentElement.onclick = () => set_show((show) => !show);
    
  • full code:

    const PanelVisbilityController: React.FC<{
      set_show_MediaStreamLocalSelfGridPanel_rst: React.Dispatch<React.SetStateAction<boolean>>;
      set_show_LobbyUserListPanel_rst: React.Dispatch<React.SetStateAction<boolean>>;
      set_show_VideoConnectionControlPanel_rst: React.Dispatch<React.SetStateAction<boolean>>;
      set_show_TextChat_rst: React.Dispatch<React.SetStateAction<boolean>>;
      set_show_DebugPanel_rst: React.Dispatch<React.SetStateAction<boolean>>;
    }> = React.memo(({ set_show_MediaStreamLocalSelfGridPanel_rst, set_show_LobbyUserListPanel_rst, set_show_VideoConnectionControlPanel_rst, set_show_TextChat_rst, set_show_DebugPanel_rst }) => {
      const [show, set_show] = React.useState<boolean>(true);
      // reversed order ...
      const actions = [
        { icon: <VideoLibraryIcon />,       name: 'MediaStream',        onClick: () => set_show_MediaStreamLocalSelfGridPanel_rst(show => !show) },
        { icon: <VideoChatIcon />,          name: 'ConnectionAnchor',   onClick: () => { console.log('// Do nothing')} },
        { icon: <VideoCameraFrontIcon />,   name: 'LobbyUserList',      onClick: () => set_show_LobbyUserListPanel_rst(show => !show) },
        { icon: <VideogameAssetOutlined  />,name: 'ControlPanel',       onClick: () => set_show_VideoConnectionControlPanel_rst(show => !show) },
        { icon: <ChatIcon />,               name: 'TextChat',           onClick: () => set_show_TextChat_rst(show => !show) },
        { icon: <BugReportIcon />,          name: 'DebugPanel',         onClick: () => set_show_DebugPanel_rst(show => !show) },
      ]; // prettier-ignore
      return (
        <SpeedDial
          ariaLabel="SpeedDial PanelVisbilityController"
          sx={{ position: 'fixed', bottom: 16, right: 16 }}
          icon={
            <SpeedDialIcon
              ref={React.useCallback((elt: HTMLElement | null | any) => {
                if (elt instanceof HTMLElement) {
                  if (elt.parentElement instanceof HTMLButtonElement) {
                    elt.parentElement.onclick = () => set_show((show) => !show);
                  } else {
                    console.warn('internal structure of material-ui SpeedDialIcon is changed, hack doesnt work, fall back to default handling');
                    elt.onclick = () => set_show((show) => !show);
                  }
                } else if (elt === null) {
                  // @do_nothing react thing ... elt is null
                } else {
                  // console.log(typeof elt);
                  // console.log(elt.constructor.name);
                  console.error('I may use the ref wrong in react,, to access to the dom element...');
                }
              }, [])}
              // onClick={() => set_show((show) => !show)}
            />
          }
          open={show}
        >
          {actions.reverse().map((action) => (
            <SpeedDialAction
              key={action.name}
              icon={action.icon}
              tooltipTitle={action.name}
              onClick={(ev) => {
                // ;not_good, clicking the icon inside also triggers; () => set_show((show) => !show);
                // ;not_good, clicking the blank region also triggers; []
                // ;not_good, clicking the blank region also triggers; You should use the stopPropagation instead:
                // ;not_good, clicking the blank region also triggers; <>
                // ;not_good, clicking the blank region also triggers; https://stackoverflow.com/questions/61649335/how-do-i-get-material-ui-speeddialaction-onclick-events-to-fire-when-speeddial-i
                // ;not_good, clicking the blank region also triggers; ev.stopPropagation();
                action.onClick();
              }}
              // open={false}
            />
          ))}
        </SpeedDial>
      );
    });
    

In a different respond post.
The implementation of e.stopPropagation(); seems to somewhat address the issue,
however, it still leads to the concern of

clicking the blank region also triggers
-- not limited solely to the blue circle button.

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

Struggling to navigate the DOM using JavaScript and looking for guidance?

I have been searching for an answer to this question without any luck. I am wondering if someone can assist me with finding a solution... I need help using JavaScript (not jQuery) to retrieve the class of the following li element when searching for ' ...

Using JavaScript's regular expressions to identify a code block that commences with a specified pattern

Currently, I am working on a JavaScript script and I am in need of a Regex pattern to quickly match "JSDocs". The specific pattern that I am trying to match looks like this: # this is block1 /// text /// text /// text /// text # this is block2 /// text // ...

What could be the reason for document.body.style.backgroundColor not working properly?

I am currently experimenting with a logic that triggers the screen to turn black upon pressing the print screen key. Despite changing the background color, it is not functioning as expected. The console has detected a change in value. What could be going ...

Guide on sending a JSON object to an EJS javascript loop efficiently

Seeking assistance with passing a Json object named myVar to the home.ejs file below. How should I assign the value to the variable called data? <table id="example" class="table table-striped table-bordered dataTable" cellspacing="0" width="100%"> ...

What is the method for transforming a JavaScript array (without an object name) into JSON format (with an object name)?

Currently, I am using an ajax query to read a local csv file and then loading the extracted values into an array. This is how the string value appears in the csv file: "Tiger","Architect","800","DRP","5421" ...

The cloned rows created with jQuery are failing to submit via the post method

Hello, I am currently working on a project in Django and could use some assistance with my JavaScript code. Specifically, I am trying to incorporate a button that adds new rows of inputs. The button does function properly as it clones the previous row usin ...

Having trouble pre-populating the input fields in my form. Any assistance would be greatly appreciated. Thank you!

I am currently diving into the world of MERN stack development and working on a basic app that involves adding, updating, and deleting items from a menu. Specifically, for the update feature, I am trying to prepopulate the input fields with existing item d ...

Is there a way to modify the color of a checkbox within MUI?

I'm currently customizing the checkbox color in Material UI while using FormIk for data submission. I aim to change the default checkbox color to red, but I'm unsure about how to achieve this. <FormGroup> <Box display=" ...

Is there a way to determine if a browser's Storage object is localStorage or sessionStorage in order to effectively handle static and dynamic secret keys within a client?

I have developed a customizable storage service where an example is getExpirableStorage(getSecureStorage(getLocalStorage() | getSessionStorage())) in typescript/javascript. When implementing getSecureStorage, I used a static cipher key to encrypt every ke ...

Can you offer guidance on how to include a MUI icon as a React component?

I am looking to utilize a custom name for the mui-icon component in order to have more control over its function. Due to implementation requirements, I need to choose a different name from the default one assigned to the icon. // Default import import ...

Subtracting 25% from the width of the web browser

After spending some time trying to solve this issue by myself, I've decided to reach out for help here where I know I can get some great responses. I am looking to determine the dimensions of the browser window minus 25%. Specifically, I have a two-c ...

Error: global not declared in the context of web3

I've been attempting to integrate Web3 into my Ionic v4 project for some time now. However, I keep encountering errors when I try to serve the project. Specifically, I receive an error message stating that Reference Error: global is not defined. Cre ...

What is causing the data element to remain unchanged within a Vue.js function and what steps can be taken to ensure its value can be updated?

Using the axios API in the created() function, I am able to access webURLs. When a mouseover event triggers a v-for handler in the HTML file, the index is obtained and assigned to the selectedState data element. Although the value of selectedState changes ...

Show or hide the legend on a highchart dynamically

I am currently utilizing highchart in my application and I am interested in learning how to toggle the visibility of the legend within the highchart. Here is what I have attempted: var options = { chart: { type: 'column&a ...

Is Typescript the Ultimate Replacement for propTypes in React Development?

After diving into Typescript for the first time and exploring related articles, it appears that when using Typescript with React, propTypes definitions may no longer be necessary. However, upon examining some of the most popular React Component Libraries: ...

Having numerous calls to isNaN within a JavaScript if-else statement

I've created a JavaScript function that generates div elements and styles them based on user input values. However, I'm facing an issue when trying to display a warning message if the input is not a number. Currently, I'm unable to create th ...

Postpone reloading automatically if a division is in view

I endeavored to develop a small project aimed at monitoring flights passing over my vicinity. Utilizing the flight-radar24 API python package, I managed to extract the necessary data. Subsequently, I designed a systemd service to execute my python script ...

CanJS utilizes mustache templates to escape HTML tags

I have a requirement to present a series of choices to the user. I am using a mustache template along with the CanJS JavaScript framework to showcase these options. The problem arises when attempting to display an option such as: Potato Rs. 12 The mustac ...

Leveraging Leaflet or any JavaScript library alongside Typescript and webpack for enhanced functionality

Important: Despite extensive searching, I have been unable to find a resolution to my issue. My current endeavor involves developing a map library through the extension of leaflet. However, it appears that I am encountering difficulties with utilizing js ...

Navigating through props provided within a setup function in Vuejs using the Composition API

I am facing an issue when trying to pass an object into a child component using props in the Composition API setup function of Vue. Instead of utilizing 'Abe', I want to run a query from firebase based on the displayName property of the user. As ...