A decorative gradient placed over an image, an icon dropped inside a button, an element that must stay visible without ever catching a single click: in all three cases, an element needs to exist visually while becoming completely transparent to mouse interaction. That is exactly what pointer-events does.
It is a discreet property, not widely known among beginners, yet it solves at once problems that would otherwise seem to require JavaScript or a full HTML reorganisation.
Definition
pointer-events determines whether an element can become the target of a pointer event: click, hover, drag and drop. Its default value, auto, lets the element react normally. Set to none, it makes the element completely invisible to the mouse: clicks and hover pass straight through it, as if it no longer existed at that exact spot, and reach whatever element sits directly underneath instead.
Concrete example: a decorative gradient blocking clicks
.card {
position: relative;
}
.card .decorative-gradient {
position: absolute;
inset: 0;
pointer-events: none;
}Without this line, this purely visual CSS gradient, placed with position: absolute over the whole card, would intercept every click meant for the image or the button it covers. pointer-events: none makes it transparent to interaction while keeping its visual effect intact.
Another use case: an icon inside a button
.button svg {
pointer-events: none;
}Without this rule, clicking precisely on the icon inside a button can trigger a slightly different behaviour than clicking the rest of the button, particularly when a script checks the exact element the event targeted. Neutralising the icon guarantees that a click anywhere on the button, icon included, always behaves the same way.
The trap: it is not real, accessible disabling
pointer-events: none only blocks the mouse. A button or link that keeps keyboard focus stays activatable with the Enter key, even while invisible to clicks, which creates an inconsistent experience between mouse and keyboard. To truly disable an interactive control, the disabled or aria-disabled attribute remains the right solution; pointer-events should only be used on purely decorative elements or very specific interface cases, never as a substitute for real disabling.
Another detail often goes unnoticed: cursor does not automatically change along with pointer-events. An element set to pointer-events: none keeps whatever cursor the element sitting right underneath would have shown, which can be surprising if the intent was to display a not-allowed icon. Getting that exact result requires combining both properties on the same element, one handling the interaction, the other purely the cursor's visual appearance.
Frequently asked questions
Is pointer-events: none enough to disable a button?
No, that is not good practice. This property only blocks mouse interaction, not the keyboard, which leaves a supposedly disabled button still triggerable by a keyboard user. The HTML disabled attribute, which also removes the element from keyboard navigation, remains the right tool for disabling a genuine interactive control.
Can only children be targeted with pointer-events, not the parent?
Yes. By setting the parent to pointer-events: none and then a specific child to pointer-events: auto, only that child becomes clickable again, while the rest of the parent lets clicks pass through to whatever sits underneath. This combination is handy for an overlay that should only let one button placed on top remain interactive.
Does pointer-events also work on touch events?
Yes, on nearly every modern browser, pointer-events applies just as well to touch as to the mouse, since both go through the same unified family of pointer events at the platform level. An element set to none therefore also becomes transparent to a finger tap on a touchscreen, with no extra configuration needed.