pointer-events
pointer-events
The pointer-events property controls whether an element can become the target of pointer events like clicks, hover states, and other pointer-based events. In other words, it lets you decide whether the browser should treat an element as interactive when the pointer is over it.
.no-pointer-events {
pointer-events: none;
}
To understand how the property works, it helps to know what the browser does before it fires a pointer event. First, it has to determine which element is under the pointer. This process is known as hit-testing. Normally, the browser chooses the topmost element under the pointer. But if that element has pointer-events set to none, the browser skips it and continues looking for the next eligible element underneath.
Once you think about pointer-events this way, most of its behavior starts to make sense. Rather than disabling events, it simply changes which element (or, in the case of SVG, which part of an element) becomes the event target in the first place.
Syntax
pointer-events: auto | bounding-box | visiblePainted | visibleFill | visibleStroke | visible | painted | fill | stroke | all | none;
- Initial:
auto - Applies to: All elements. In SVG, it applies to container elements, graphics elements, and the
<svg>element. - Inherited: Yes
- Computed value: Specified keyword
- Animation type: discrete
Values
pointer-events: auto;
pointer-events: none;
/* SVG values */
pointer-events: visiblePainted;
pointer-events: visibleFill;
pointer-events: visibleStroke;
pointer-events: visible;
pointer-events: painted;
pointer-events: fill;
pointer-events: stroke;
pointer-events: bounding-box;
pointer-events: all;
/* Global values */
pointer-events: inherit;
pointer-events: initial;
pointer-events: revert;
pointer-events: revert-layer;
pointer-events: unset;
Besides the standard CSS global values shown above, pointer-events defines eleven keyword values. You'll use auto and none with both HTML and SVG elements, while the other nine are SVG-only and provide finer control over which parts of a graphic can receive pointer events.
auto: The default value. The element behaves normally and can receive pointer events. In SVG, this behaves the same asvisiblePainted.none: The element itself can't become the target of pointer events, meaning it can't be clicked or hovered. Instead, the browser targets whatever is underneath it.
SVG-only values
visiblePainted: The element only receives pointer events when it's visible (visibility: visible) and the pointer is over a painted part of the graphic. In other words, it's over a filled area (fillis notnone) or a stroked edge (strokeis notnone).visibleFill: The element only receives pointer events when it's visible and the pointer is over its fill, regardless of the value of thefillproperty, meaning it can even be set tonone.visibleStroke: The element only receives pointer events when it's visible and the pointer is over its stroke, regardless of the value of thestrokeproperty.visible: The element only receives pointer events when it's visible and the pointer is over either its fill or stroke, regardless of the values of thefillandstrokeproperties.painted: The element only receives pointer events when the pointer is over a painted part of the graphic (its fill or stroke), regardless of the value of thevisibilityproperty.fill: The element only receives pointer events when the pointer is over its fill, regardless of the values of thefillorvisibilityproperties.stroke: The element only receives pointer events when the pointer is over its stroke, regardless of the values of thestrokeorvisibilityproperties.bounding-box: The element receives pointer events anywhere inside its bounding box-the smallest rectangle that completely surrounds it-regardless of its shape, even if parts of that area aren't painted.all: The element receives pointer events when the pointer is over either its fill or stroke, regardless of the values of thefill,stroke, orvisibilityproperties.
Children can opt back in
One thing that's easy to miss is that pointer-events is an inherited property. Setting pointer-events to none on a parent means its children inherit that value as well. However, any child can override the inherited value by setting pointer-events back to auto (or another valid value).
.parent {
pointer-events: none;
}
.child {
pointer-events: auto;
}
In this example, the parent ignores pointer events, but the child can still become their target.
A common use case is a modal. You might use a full-page container to center the modal, but that container also covers the entire viewport. Without changing its pointer-events value, it prevents pointer events from reaching the elements underneath it. Setting pointer-events to none on the container fixes that, but because the property is inherited, you'll also need to restore the modal itself with pointer-events set to auto.
In the following demo, when the pointer-events property is specified as none you can interact with the background buttons even though they are behind the overlay.
Event propagation still works
The pointer-events property only determines which element becomes the event target. It doesn't change how events travel through the DOM afterward. For example, if a child with pointer-events: auto is clicked inside a parent with pointer-events: none, the child still becomes event.target. From there, the event follows its normal capture and bubble phases, so event listeners attached to the parent still run.
In other words, pointer-events affects target selection, not event propagation. In the following demo, you can see how the parent with pointer-events: none can still receive click, pointerenter, and pointerleave when you click or move the pointer into or out of its interactive child.
pointer-events doesn't disable an element
The pointer-events property only prevents the element from becoming the target of pointer events. Therefore, the element can still receive keyboard focus with the Tab key, and users can continue interacting with it using the keyboard if it's otherwise focusable.
If you need to disable a native form control, use the disabled attribute instead. And if your goal is to make an entire section of the page completely non-interactive-including pointer input, keyboard focus, and the accessibility tree-the inert attribute is a better choice.
pointer-events doesn't prevent text selection
Setting the pointer-events property to none doesn't stop users from selecting text. For example, users can still select the text by pressing Ctrl/Cmd + A on the keyboard. That's because text selection isn't determined by whether an element can become the target of pointer events.
If your goal is to prevent text from being selected, use the user-select property instead.
.avoid-user-selection {
user-select: none;
}
Try selecting the text in each block below.
Demo
When building a navigation menu, a common pattern is to hide a submenu by setting its opacity to 0 and then make it visible when the user hovers over its parent menu item. The problem is that the submenu is still there, so it can still receive pointer events even though you can't see it.
Below, you can see two identical menus. One hides its submenu using only opacity, while the other also uses pointer-events. Hover over the hidden submenu area and try interacting with the content behind it to see how pointer-events prevents invisible elements from getting in the way.
Also, to better understand how each SVG value of this property works, pick one from the dropdown and move your pointer around the ring: over its filled band, inside its hollow center, and over the empty corners of the dashed bounding box. Notice how the interactive area changes with each value.
This works great for disabling hover/active states on disabled buttons and form elements.
but right click is working still
@deepak – "what's a right click?" –Mac users for 20 years. Right-clicking is a mouse action, but not a pointer-event. The HTML API for the DOM doesn't define an "onrightclick" event and there is no native listener for the event. The closest match for handling right clicking is the newer context menu API for the popup menu, but this is not directly a result of right clicking, as any keyboard key or interactive device can be set to open the context menu.
@Tony – brush up on your JS knowledge. Right click is natively handled via onclick where event.button == 2 – see https://developer.mozilla.org/en-US/docs/Web/Reference/Events/click. And don't brag about being a Mac user for 20 years, it's like you're asking for sarcasm ;)
Remember you already can edit the text on inputs by pressing Tab key and… just typing =D. You must have to disable states on form elements and set readonly="readonly"…
Unfortunately these tricks are ineffective if you have "hover CSS" inside the SVG file.
I've tested the above demo in IE11 and it works. Woohoo! It works, but note that inside an element where pointer-events have been set to none, for IE11 to take notice of a pointer-events: auto, the target element must also have a CSS position other than static:
Ref: https://coderwall.com/p/s8pjpg
@RK – Thank you kind sir
The only issue I have with it for links is it doesn't display a link's Title on hover.
There is a mismatch between pointer-events and oncontextmenu
Superb! Really need more time to experiment with SVG and this seems like a way better solution than mitigating event bubbles in JavaScript.
I've noticed which Canvas you register click events on the container of a circle, but with SVG the circle is almost like a clipMask (or Mask in Flash). I've attempted to use clipMask in SVG and place the foreignObject inside of the clipMask only to discover that clipMask doesn't accept the foreignObject. Does anyone have any ideas how you would add circular objects that rotate in a circle, inside of SVG where whatever is behind the outer edge of the circle is not registered as an event by the SVG above it? Think of like a rotary telephone with a switch on the side or something.
This will certainly be a handy way of allowing events to "pass through" elements, and for temporarily disabling pseudo states. But I'm struggling to see how it's of much use for anything else. How, for example, would you implement drag and drop using pointer events, without also blocking scale and zoom gestures? It doesn't appear to be possible. Microsoft's suggestion is to set touch-action to either pan-x or pan-y - e.g. if it's set to pan-y then vertical swiping scrolls the page, while horizontal swiping fires events you can use for drag and drop. So the drag action would only work if you did it horizontally. That might be acceptable for applications, where page scaling is disabled, but it's of no use on web pages, where the scaling might be large enough that the page scrolls in both directions. And I don't think it's particularly intuitive either way. Pointer events might be a useful high-level abstraction, but they're no substitute for proper low-level touch events.
hmmm, not what I expected…in this example it does not appear that it passes events to elements below the stacking order, nor z-index, as this article suggests so this is useless if you have a full viewport overlay and wish to interact with elements below (underneath) it. Am I reading this wrong? http://codepen.io/pingram3541/pen/hvtFH (try clicking on div.two "through" div.four) it doesn't work nor does it show the hover state for the anchor. Example has both an inherit anchor as well as js event handler.
I take that last post back, partially…I can't believe I did this as I almost never use IE except for testing for the stuff it breaks…but sure enough I was using IE when I built the codepen lol. The CSS rule works on webkit. =) lol, wish I could edit my comments so as not to pollute this thread…
Found a solution for IE, but it isn't perfect…since the WC3 spec is for SVG, if the overlay is defined as an SVG, pointer-events are in fact passed through. And a possible JS solution – http://www.vinylfox.com/forwarding-mouse-events-through-layers/
This line of CSS is great – can cancel links without touching PHP: pointer-events: none; I have used it to cancel top level link menu in WP. If it affects also sub menus then put pointer-events: auto; on the sub menu CSS. Works great.
It seems it doesn't work on fixed elements….. http://www.cybertechquestions.com/position-fixed-element-not-passing-through-pointer-event-click_87096.html
Actually, it works on fixed elements. I have a fixed user bar with some icons in it (links to login and such). As a responsive layout the menu collapses into a fixed menu bar (transparent background) which is stacked above the user bar. The icons in the user were no longer accessible. By using pointer-events:none on the menu bar and pointer-events:auto on the menu items, everything works as expected, even through fixed elements.
THIS JUST SAVED MY LIFE. I was doing an overlay over a gallery, where I would display a magnifying glass on hover. The problem is that the overlay layer was taking precedence over the anchor, and the Foundation Clearing gallery I was using relies on what is clicked to identify the gallery content. pointer-events:none on the overlay div and it was all solved. :D
I'd much rather there be separate properties for "click-events" and "hover-events" so I could control them separately. After all a "pointer" isn't even an event, lol. I guess touch-events could be broken into swipe-events and tap-events as well, but I've not found a use case for that, yet.
I second this motion ^_^
Comments
No comments yet. Start the discussion.