react-bootstrap: Overlay trigger does not trigger when child button is disabled

An overlay trigger that wraps a button with a prop of disabled will not show overlay on hover. Not sure if this is considered a bug or a feature. In my specific case I’d like to disable a button and then give the reason on hover.

Displays overlay:

<OverlayTrigger
  overlay={<Tooltip>Some overlay</Tooltip>}>
  <Button>Some button</Button>
</OverlayTrigger>

Does not display overlay:

<OverlayTrigger
  overlay={<Tooltip>Some overlay</Tooltip>}>
  <Button disabled>Some button</Button>
</OverlayTrigger>

About this issue

  • Original URL
  • State: closed
  • Created 8 years ago
  • Reactions: 10
  • Comments: 15 (2 by maintainers)

Most upvoted comments

Yeah mouse events don’t fire on disabled elements (browser behavior), so hover is going to fail there. Instead wrap your button in a span or other inline element. See also this note about it here: http://getbootstrap.com/javascript/#tooltips

This thread pointed me in the right direction to get this working for my use case. JSBin here: http://jsbin.com/midixo/edit in case its of use to anyone.

Indeed, can confirm that :

  • using an inline wrapper does not work anymore
  • adding pointer-events: all; does not work anymore
  • the workaround with the empty div provided by @simarsenault works
  • this issue needs re-opening @jquense

It seems something has changed in the newer versions that broke the old trick. @simarsenault’s suggested workaround does the job (thanks for that by the way!), but is definitely far from optimal. Until someone finds a better alternative perhaps it is best to reopen the issue, WDYT?

For my fellow Googlers: I wasn’t able to make it work with either wrapping the button inside a span/div or the CSS pointer-events: all;. However, I made it work by creating a div with position: absolute above the button:

public render(): JSX.Element {
	const overlay: JSX.Element = <Popover id={`overlay`}>
		<Popover.Content>
			Hello :)
		</Popover.Content>
	</Popover>;
	
	return <div>
		<OverlayTrigger placement="auto" overlay={overlay}>
			<div style={{ position: "absolute", top: "0", left: "0", width: "100%", height: "100%", cursor: "not-allowed", zIndex: 2 }}/>
		</OverlayTrigger>
		
		<MyCustomButton
			...
		/>
	</div>
}

Here’s a component that does the work-around: react-bootstrap-tooltip-button

Wrapping a button in a <div> breaks the bootstrap styling for ButtonGroup and ButtonToolbar because those rules expect a button, not a div. This component fixes that as well.

This can also be solved with CSS: pointer-events: all; This seems a little cleaner than polluting your markup?

Find the solution here in the official doc: https://react-bootstrap.github.io/components/overlays/#disabled-elements

As a workaround, you’ll want to trigger the overlay from a wrapper <div> or <span> and override the pointer-events on the disabled element.

import Button from 'react-bootstrap/Button';
import OverlayTrigger from 'react-bootstrap/OverlayTrigger';
import Tooltip from 'react-bootstrap/Tooltip';

function DisabledExample() {
  return (
    <OverlayTrigger overlay={<Tooltip id="tooltip-disabled">Tooltip!</Tooltip>}>
      <span className="d-inline-block">
        <Button disabled style={{ pointerEvents: 'none' }}>
          Disabled button
        </Button>
      </span>
    </OverlayTrigger>
  );
}

export default DisabledExample;