Material-UI Tooltip automatically opens (displays unexpectedly) after button got enabled - reactjs

I suppose that the state change of the button (enabled or disabled) is causing the issue.
I have 5 action buttons (create, delete, edit, save and cancel).
All buttons start disabled except the Create button.
When I click the Create button, it becomes disabled and the Save and Cancel buttons become enabled. When it occours, the Save or Cancel tooltip pops up. Sometimes both of them pop up, sometimes only one of them pops up.
At the first time, I thought that it was happening in response to focus events. Then I try to disable the tooltip response to focus events setting disableTriggerFocus={true}, but it doesn't work.
Here's the code for ActionButton:
import Tooltip from "#material-ui/core/Tooltip";
const ActionButton = ({ buttonIcon, onClick, disabled, tooltip }) => {
return (
<>
<Tooltip
title={disabled ? "" : tooltip}
placement="top"
arrow
disableTriggerFocus={true}
>
<Button onClick={onClick} disabled={disabled}>
<ButtonIcon tag={buttonIcon} />
</Button>
</Tooltip>
</>
);
};

The triggering of the tooltip for hovering is based on the mouseOver and mouseLeave events. mouseOver events get triggered for disabled buttons, but mouseLeave events do not. When you hover over a disabled button it triggers opening the tooltip, but when you leave the disabled button the mouseLeave event is not triggered so the tooltip stays open.
You have code (title={disabled ? "" : tooltip}) that suppresses the tooltip text when it is disabled, but the tooltip still thinks it is "open". Then when you enable the button, the text of the tooltip is restored and immediately displays. So which buttons this occurs on depends on which disabled buttons you happened to hover over while they were disabled.
You can fix this by explicitly controlling the open state of the Tooltip using the open, onOpen, and onClose properties. onOpen fires when Tooltip thinks it should open and onClose fires when Tooltip thinks it should close, but you can combine this information with additional information (e.g. the disabled state) to decide on the value of the open property.
Below is a working version of ActionButton. The useEffect call is to handle the case where the tooltip is open as you click on the button. If the button is disabled by the click, then onClose won't fire when leaving the button since the mouseLeave event won't be triggered for the disabled button, so the effect handles closing the tooltip in that case.
import Tooltip from "#material-ui/core/Tooltip";
import { useState, useEffect } from "react";
const ActionButton = ({ buttonIcon, onClick, disabled, tooltip }) => {
const [open, setOpen] = useState(false);
useEffect(() => {
if (disabled && open) {
setOpen(false);
}
}, [disabled, open]);
return (
<>
<Tooltip
title={tooltip}
placement="top"
arrow
onOpen={() => {
if (!disabled) {
setOpen(true);
}
}}
onClose={() => setOpen(false)}
open={open}
>
<Button onClick={onClick} disabled={disabled}>
<ButtonIcon tag={buttonIcon} />
</Button>
</Tooltip>
</>
);
};
Related answers:
Programmatically open Tooltip in Material-UI
Is it possible to render a tooltip on a disabled Material-UI <Button> within a <ButtonGroup> without breaking the layout?

Related

React button with icon onClick presses icon and not button

I have a button with an icon in it. It all looks good and I though everything worked properly but then I started getting undefined behaviors. It turns out that the onClick of the button e.target return either the button press, a polygon or an SVG. It depends if I click the corner of the button, then e.target is the button, if I click on the icon I either get a e.target polygon or svg. I only want to get the button. This is the code for generating the button:
<CButton
color="danger"
value={[name, name2, name3]}
onClick={handleUnlink}>
{<CIcon icon={cilX} />}
</CButton>
This is the code for onClick:
const handleUnlink = (e) => {
console.log(e.target)
};
How do I make sure that a user that accedently presses the CIcon inside the button is still only triggering a button press?
You can use the e.currentTarget property to make sure that a user that accedently presses the CIcon inside the button is still only triggering a button press.

Unable to Stop Propogation of Checkbox when on top of Collapse with Antd 4.x Library

I am using Antd 4.x library. I have a Collapse and a popover that shows on Click of button on Collapse which has a Checkbox in it. I would like to Stop Propagation when checking/unchecking the checkbox, i.e. the Collapse opens/closes when checking/unchecking
Although when I click on Label of Checkbox the Collapse doesn't open/close but when the I do it on the checkable part of checkbox it happens.
I would like to Stop the open/close of Collapse when checking/unchecking of checkbox on popover
Demo Link to show the issue
TIA
You can wrapped your Panel extra content in a div and add onClick to stopPropagation. Also, you do not have to handle stopPropagation in Setting Button & Checkbox.
const onChange1 = (e: { target: { checked } }) => {
console.log(`checked = ${e.target.checked}`);
};
const genExtra = () => (
<div onClick={(e) => e.stopPropagation()}>
<Popover content={<Checkbox onChange={onChange1}>Checkbox</Checkbox>} title='Title'>
<SettingOutlined />
</Popover>
</div>
);
First of all, you have to understand that when an event occurs, the event always has an event source, that is, the object that caused the event. An event cannot be generated out of thin air. This is the occurrence of an event.
When the event occurs, the event will start to propagate. In your case, when we click the checkbox, a click event will be generated, but the checkbox cannot handle this event. The event must be propagated from the checkbox to reach the code that can handle the event. (for example, we assign a function name stopPropagation to the Fragment's onClick property, which is to let "stopPropagation" handle the Chekbox's click event).
import React, { Fragment } from "react";
function stopPropagation(e) {
//The stopPropagation() method of the Event interface prevents further propagation of the current event in the capturing and bubbling phases.
if (e && e.stopPropagation) {
e.stopPropagation();
} else {
//If it is IE browser
window.event.cancelBubble = true;
}
}
const genExtra = () => (
<Fragment onClick={(e) => stopPropagation(e)}>
<Popover
content={<Checkbox onChange={onChange1}>Checkbox</Checkbox>}
title="Title"
>
{/* <Button type="primary" shape="circle" icon={<SearchOutlined />} /> */}
<SettingOutlined
onClick={(event) => {
event.stopPropagation();
}}
/>
</Popover>
</Fragment>
);
For your reference: https://developer.mozilla.org/en-US/docs/Web/API/Event/stopPropagation

The action menu is not getting closed even if I click somewhere on page, the menu remains open until I explicitly click on the Action button again

//This is dropdown component
const Dropdown: FC<any> = ({ list, item, title },props) => {
const isDisabled = item && item.users.length > 0 ? false : true;
const [show, setShow] = useState(false);
const toggleMenu = () => {
setShow(!show);
};
return (
<div>
<Button
title={title || "Action"}
onClick={toggleMenu}
iconName="downarrow"
iconPosition="left"
variant="outlined"
color="primary"
/>
)
The action menu is not getting closed even if I click somewhere on page, the menu
remains open until I explicitly click on the Action button again.
If you want the action menu to close when you click anywhere on the page using onClick won't help it. Use onBlur and use it on the button as -
<Button
title={title || "Action"}
onClick={toggleMenu}
onBlur={() => setShow(true)}
iconName="downarrow"
iconPosition="left"
variant="outlined"
color="primary"
/>
Or alternatively, what you can do is -
Create a reference to your outer div.
Add event listener mousedown (or click) to the document whenever this component appears on screen (eg. mount) and also don’t forget to remove the event on unmount too.
Inside the event (handleClick) this.{Any ref name you give}.contains(e.target) will return true if whatever you are clicking is inside the “node” ref.
Now you have it, you can now do whatever you feel like, close the modal, close the dropdown menu list, anything is allowed.
The above 4 points were taken from the article - https://medium.com/#pitipatdop/little-neat-trick-to-capture-click-outside-react-component-5604830beb7f.

React Materials-UI disable a button in a handler

Trying to disable a button after the user clicks on it, but from a handler function.
I have referenced these two similar questions:
React Material UI: How to give a button a custom color when disabled?
Change disable attribute in react select with material UI
I thought changing the color would be a good practice step, but that didn't work. When I use color='primary' the button is blue, and that's what I want for the initial state. However, when the page loads, the button is now gray (looks disabled, but the mouse can still click on it).
My original blue button:
<Button id='UploadButton' onClick={uploadButtonClicked}
variant="contained" color="primary">Upload</Button>
My revised button (trying to use state for color):
<Button id='UploadButton' onClick={uploadButtonClicked}
disabled="{uploadButtonDisabled}"
variant="contained"
color="{uploadButtonColor}">Upload</Button>
My state & handler:
const [uploadButtonColor, setUploadButtonColor] =
React.useState('primary');
const [uploadButtonDisabled,
setUploadButtonDisabled] = React.useState('false');
const uploadButtonClicked = () => {
// will post data to a REST API here, then disable the button
setUploadButtonColor('red')
setUploadButtonDisabled('true')
}
Do I need to use color schema to make it look disabled, or can I just add the disabled word, or set disabled to true?
This is how the doc shows a disabled button:
<Button variant="outlined" disabled>
Upload
</Button>
Do not put quotes around the property/substitution values
disabled={isDisabled} not disabled='{isDisabled}' (and same with color).
You can use this :
import Button from "#material-ui/core/Button";
function SampleButtons(props) {
let [isDisabled, setIsDisabled] = React.useState(false)
return (
<React.Fragment>
<Button variant="contained" onClick={() => setIsDisabled(true)} disabled={isDisabled}>Button</Button>
</React.Fragment>
);
}

Using hover and click in materia ui ToolTip causes issues in closing the tooltip

I am able to use hover and click functionality separately in material ui Tooltip.
Now i want following functionality using both.
when i hover the tooltip should open. If i click the tooltip should remain open unless i close it.
I have done following to achive hover and onclick
1. initially disableHoverListener is false as a result am able to show tooltip on hover
2. when i click on the button to open the tool tip i set open = true. The tooltip remains open. If i try to close the tool tip am able to set the open = false. but the tooltip doesnot close until i move the mouse.
Can someone guide me in solving the problem
Here is the code for whatever I could understand from your description.
You want the tooltip to show on hover (default behaviour). But if you make it controlled component. i.e you want to set open true on click and false otherwise the default behaviour won't work.
Working Example: CodeSandbox
Here's code hope it helped.
const [show, setShow] = React.useState(false);
const handleClick = () => {
if (show) {
setShow(false);
} else {
setShow(true);
}
};
return (
<div
style={{ display: "inline" }}
onMouseOver={() => setShow(true)}
onMouseLeave={() => setShow(false)}
>
<Tooltip title="You want to see me!" open={show} onClick={handleClick}>
<IconButton aria-label="delete">
<DeleteIcon />
</IconButton>
</Tooltip>
</div>
);

Resources