There’s no reason to use pointer-events for HTML elements

UPDATE: Some people have pointed out some genuinely great use cases for this property which I've listed at the end of the article. I still stand by all the points I made against the use cases I pointed out in this article, but I now believe there are some good reasons to use pointer-events for HTML elements!

The pointer-events CSS property controls if and how elements can be targeted by pointer inputs such as a mouse. It initially formed part of the specification for SVGs to allow more fine-tuned control of where in a shape a user could interact with.

This is useful, for example, if we have shapes placed on top of each other and want the shape that is not necessarily at the top of the stack to receive (or not receive) mouse events. In the example below, I have a rectangle placed behind a circle. The circle has a stroke but no fill, meaning that the rectangle behind it is visible.

<style>
circle { pointer-events: visiblePoint; }
</style>

<svg viewBox="0 0 20 10" xmlns="https://www.w3.org/2000/svg">
<rect x="0" y="0" height="10" width="10" fill="black" />
<circle cx="5" cy="5" r="3" stroke="yellow" />
</svg>

By applying pointer-events: visiblePoint; to the circle, it allows the middle of the circle to be clicked, even though it appears that we are clicking the rectangle behind it.

Try clicking in the middle of the circle below. Even if you click on an area that looks like it belongs to the rectangle behind, the circle receives the click event and the stroke changes colour.

document.querySelector("circle").addEventListener("click", (e) => {
const randomColour = Math.round(Math.random() * 0xFFFFFF);
e.target.style.stroke = `#${randomColour.toString(16).padStart(6,"0")}`;
});

pointer-events and HTML elements #

Since the initial specification in SVG, the point-events property has made its way to CSS. Although limited, we can now use the pointer-events property with regular HTML elements.

<style>
button:hover, button:focus { background-color: #ffdb3a; }
</style>

<button>Hover or focus over me</button>
<button style="pointer-events: none;">Hover or focus over me too</button>

When used with non-SVG elements, only three values are available - inherit, auto and none.

The inherit value works as it does with any other CSS property. When applied to an element, it will use the same value for the property as the element’s parent.

The auto value will restore the default functionality. That is, the pointer events for the element will behave as it does without the pointer-events property.

Finally, we have none. As we saw in the example above, this value will prevent all pointer events - hover, active, click - from being applied to the element.

Reasons to (not) use pointer-events: none #

As you can tell from the title of this article, my opinion is that there is no reason to use the pointer-events: none CSS rule on non-SVG, and by extension non-graphical, HTML elements.

My main reason for thinking so is because, by definition, this CSS rule will only be used when the HTML order would result in the element being able to be interacted with. The purpose of this rule seems to be to change source order in a pretty significant way.

Doing some research, I’ve come across a few scenarios in which people use this rule. Here’s what they are, and why I think they aren’t the best reasons.

Disabling interactive elements #

The most popular use case I have come across for the pointer-events: none rule is to stop users from interacting with disabled elements, such as submit buttons or input fields.

<style>
.disabled {
pointer-events: none;
}
</style>

<form>
<button class="disabled">Submit</button>
</form>
Don’t do this!

This isn’t an effective way to disable a form field because it only affects pointer events. Users can still interact with the element if navigating using a keyboard and there is no communication to assistive technology that the button is actually disabled.

A much better solution would be to use the disabled attribute in addition to visual styles to let the user know that the button is disabled.

<style>
[disabled] {
cursor: not-allowed;
}
</style>

<form>
<button disabled>Submit</button>
</form>
Better alternative

If we’re using the disabled attribute, there would be no need for the pointer-events: none rule, as the button will be properly disabled to all inputs.

Overlays #

Another example I’ve seen for the pointer-events: none rule is to allow the content behind an overlay to remain interactive.

In this case, it seems almost counterproductive to allow pointer events to the elements behind the overlay. Typically, when an overlay is used, it is a visual indication that only the elements within a restricted section, usually a modal, should be interacted with. For example, it is recommended that keyboard focus should be restricted to elements within a modal if it is active.

Therefore, it seems like cases in which an overlay is used are the exact cases where you would not want users to be able to click on elements behind the overlay.

Targeting specific children of interactive elements #

One interesting example of the pointer-events: none rule I’ve seen is to restrict the interactive sections of certain interactive elements. For example, let’s say we have a button with some text and an icon, and we only want the click of the icon to trigger the behaviour.

<button style="pointer-events: none;">
<img src="icon" alt="Icon" style="pointer-events: auto;">
<span>Click the icon to do stuff!</span>
</button>

This actually does have some benefit, as the text content and label remains within the <button> element. However, I think a better and more semantic solution would be to restructure the markup.

<button aria-labelled-by="label">
<img src="icon" alt="Icon">
</button>

<span id="label">Click the icon to do stuff!</span>
Better alternative

This way, it is clear from the markup alone what each element is for and what each element will do. The <span> is purely to label, whereas the <img> is what is interactive. Looking at this markup as compared to the previous solution, it is much clearer what the abilities of the elements are.

Is there any reason to use pointer-events for non-SVG elements? #

As I’ve said, which is purely my opinion, I don’t think there is a reason to use pointer-events for regular, interactive, HTML elements. However, it exists in CSS which makes me think it might have some use I’m not thinking of. I would love to hear from you if you’ve found any genuinely good use case for it.


UPDATE: Here's some answers I've already got from people who have found some use cases for pointer-events: none on regualr HTML elements.

Also, on https://t.co/sCMU334ga8 it's used on layout elements where the children of a flexbox should be interactive, but clicks between them should fall to elements in the background — Jake Archibald (@jaffathecake) December 17, 2018

Here's one of the examples. This div is pointer-events:none, but all the children are pointer-events:auto.

That means you can click through to the canvas in between the buttons. pic.twitter.com/Ua5oKKFPP7 — Jake Archibald (@jaffathecake) December 17, 2018

- making labels inside an input non-responsive, such as the unit of measurement, which typically floats inside the input to the right side. — Dan Burzo, birdsite edition (@danburzo) December 17, 2018

- for CSS-only tooltips (with the :before pseudo-element and generated content), I'm assuming we have pointer-events: none on them to avoid weird hover effects. - for enhancing performance while transforming some things (I need to source this statement) — Dan Burzo, birdsite edition (@danburzo) December 17, 2018

Keep in touch KeepinTouch

Subscribe to my Newsletter 📥

Receive quality articles and other exclusive content from myself. You’ll never receive any spam and can always unsubscribe easily.

Elsewhere 🌐