-
Notifications
You must be signed in to change notification settings - Fork 34
/
index.html
1621 lines (1522 loc) · 150 KB
/
index.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
<!DOCTYPE html>
<html lang="en">
<head>
<title>Pointer Events</title>
<meta http-equiv='Content-Type' content='text/html;charset=utf-8'/>
<script src='https://www.w3.org/Tools/respec/respec-w3c' class='remove' defer></script>
<script class='remove'>
var respecConfig = {
specStatus: "ED",
shortName: "pointerevents3",
subtitle: "Level 3",
edDraftURI: "https://w3c.github.io/pointerevents/",
prevRecShortname: 'pointerevents',
github: "https://github.com/w3c/pointerevents/",
testSuiteURI: "https://wpt.fyi/pointerevents/",
caniuse: "pointer",
formerEditors: [
{
name: "Matt Brubeck",
company: "Mozilla", companyURL: "https://www.mozilla.org/",
w3cid: '45617'
},
{
name: "Rick Byers",
company: "Google", companyURL: "https://www.google.com/" ,
w3cid: '55724'
},
{
name: "Navid Zolghadr",
company: "Google", companyURL: "https://www.google.com/" ,
w3cid: '92361'
}
],
editors: [
{
name: "Patrick H. Lauke",
company: "TetraLogical", companyURL: "https://tetralogical.com/",
w3cid: '35129'
}
],
group: "pointer-events",
wgPublicList: "public-pointer-events",
lint: {
"check-punctuation": true
},
noIDLSorting: true,
doJsonLd: true,
xref: {
specs: ["uievents"],
profile: "web-platform"
},
mdn: "pointerevents"
};
</script>
<style>
.issue {background: #fcc !important;}
pre.idl::before, pre.example::before { font-family: sans-serif !important; }
ol:not([data-class='note-list'])>li { margin-bottom: 1em; }
</style>
</head>
<body>
<section id='abstract'>
<p>The features in this specification extend or modify those found in Pointer Events, a W3C Recommendation that describes events and related interfaces for handling hardware agnostic pointer input from devices including a mouse, pen, touchscreen, etc. For compatibility with existing mouse based content, this specification also describes a mapping to fire Mouse Events for other pointer device types.</p>
</section>
<section id="sotd">
<p>This specification is an update to [[PointerEvents2]] which was shipped broadly by Google Chrome and Microsoft Edge and Mozilla Firefox.
Level 3 includes editorial clarifications and new features that facilitate more use cases, in an effort to enable wider developer and browser adoption.</p>
</section>
<section id="intro" class="informative">
<h1>Introduction</h1>
<p>Today, most [[HTML]] content is used with and/or designed for mouse input. Those that handle input in a custom manner typically code to [[UIEVENTS]] Mouse Events. Newer computing devices today, however, incorporate other forms of input, including touchscreens, pen input, etc. Event types have been proposed for handling each of these forms of input individually. However, that approach often incurs unnecessary duplication of logic and event handling overhead when adding support for a new input type. This often creates a compatibility problem when content is written with only one device type in mind. Additionally, for compatibility with existing mouse-based content, most <a data-lt="user agent">user agents</a> fire Mouse Events for all input types. This makes it ambiguous whether a Mouse Event represents an actual mouse device or is being produced from another input type for compatibility, which makes it hard to code to both device types simultaneously.</p>
<p>To reduce the cost of coding to multiple input types and also to help with the above described ambiguity with Mouse Events, this specification defines a more abstract form of input, called a <a>pointer</a>. A pointer can be any point of contact on the screen made by a mouse cursor, pen, touch (including multi-touch), or other pointing input device. This model makes it easier to write sites and applications that work well no matter what hardware the user has. For scenarios when device-specific handling is desired, this specification also defines properties for inspecting the device type which produced the event. The primary goal is to provide a single set of events and interfaces that allow for easier authoring for cross-device pointer input while still allowing for device-specific handling only when necessary for an augmented experience.</p>
<p>An additional key goal is to enable multi-threaded user agents to handle <a>direct manipulation</a> actions for panning and zooming (for instance, with a finger or stylus on a touchscreen), without blocking on script execution.</p>
<div class="note">
<p>While this specification defines a unified event model for a variety of pointer inputs, this model does not cover other forms of input such as keyboards or keyboard-like interfaces (for instance, a screen reader or similar assistive technology running on a touchscreen-only device, which allows users sequential navigation through focusable controls and elements). While user agents might choose to also generate pointer events in response to these interfaces, this scenario is not covered in this specification.</p>
<p>In the first instance, authors are encouraged to provide equivalent functionality for all forms of input by responding to high-level events such as <code>focus</code>, <code>blur</code> and <code>click</code>. However, when using low-level events (such as Pointer Events), authors are encouraged to ensure that all types of input are supported. In the case of keyboards and keyboard-like interfaces, this might require the addition of explicit keyboard event handling. See <a href="https://www.w3.org/TR/WCAG/#keyboard-accessible"><cite><abbr title="Web Content Accessibility Guidelines">WCAG</abbr> Guideline 2.1 Keyboard Accessible</cite></a> [[WCAG21]] for further details.</p>
</div>
<figure id="figure_martini_glass">
<img src="images/pointer.png" alt="Pointer input combines input from mouse, pen, touch, etc.">
<figcaption>A pointer is a hardware agnostic representation of input devices that can target a specific coordinate (or set of coordinates) on a screen.</figcaption>
</figure>
<p>The events for handling generic pointer input look a lot like those for mouse: {{GlobalEventHandlers/pointerdown}}, {{GlobalEventHandlers/pointermove}}, {{GlobalEventHandlers/pointerup}}, {{GlobalEventHandlers/pointerover}}, {{GlobalEventHandlers/pointerout}}, etc. This facilitates easy content migration from Mouse Events to Pointer Events.
Pointer Events provide all the usual properties present in Mouse Events (client coordinates, target element, button states, etc.) in addition to new properties for other forms of input: pressure, contact geometry, tilt, etc. So authors can easily code to Pointer Events to share logic between different input types where it makes sense, and customize for a particular type of input only where necessary to get the best experience.</p>
<p>While Pointer Events are sourced from a variety of input devices, they are not defined as being generated from some other set of device-specific events. While possible and encouraged for compatibility, this spec does not require other device-specific events be supported (e.g. mouse events, touch events, etc.). A user agent could support pointer events without supporting any other device events. For compatibility with content written to mouse-specific events, this specification does provide an optional section describing how to generate <a>compatibility mouse events</a> based on pointer input from devices other than a mouse.</p>
<div class="note informative">
<p>This specification does not provide any advice on the expected behavior of user agents that support both Touch Events (as defined in [[TOUCH-EVENTS]]) and Pointer Events. For more information on the relationship between these two specifications, see the <a href="http://www.w3.org/community/touchevents/">Touch Events Community Group</a>.</p>
</div>
</section>
<section id="conformance">
</section>
<section class="informative">
<h1>Examples</h1>
<p>The following are basic examples that demonstrate how some of the APIs in this specification might be used by authors. Further, more specific examples are provided in the relevant sections of this document.</p>
<pre id="example_1" class="example" title="Feature detection and event binding">
<code>/* Bind to either Pointer Events or traditional touch/mouse */
if (window.PointerEvent) {
// if Pointer Events are supported, only listen to pointer events
target.addEventListener("pointerdown", function(e) {
// if necessary, apply separate logic based on e.pointerType
// for different touch/pen/mouse behavior
...
});
...
} else {
// traditional touch/mouse event handlers
target.addEventListener('touchstart', function(e) {
// prevent compatibility mouse events and click
e.preventDefault();
...
});
...
target.addEventListener('mousedown', ...);
...
}
// additional event listeners for keyboard handling
...</code>
</pre>
<pre id="example_2" class="example" title="Detecting the type of input from a user">
<code>window.addEventListener("pointerdown", detectInputType);
function detectInputType(event) {
switch(event.pointerType) {
case "mouse":
/* mouse input detected */
break;
case "pen":
/* pen/stylus input detected */
break;
case "touch":
/* touch input detected */
break;
default:
/* pointerType is empty (could not be detected)
or UA-specific custom type */
}
}</code></pre>
<pre id="example_3" class="example" title="Resizing an element to match the contact geometry">
<code><div style="position:absolute; top:0px; left:0px; width:100px;height:100px;"></div>
<script>
window.addEventListener("pointerdown", checkPointerSize);
function checkPointerSize(event) {
event.target.style.width = event.width + "px";
event.target.style.height = event.height + "px";
}
</script></code>
</pre>
<pre id="example_4" class="example" title="Firing untrusted pointer events from script">
<code>const event1 = new PointerEvent("pointerover",
{ bubbles: true,
cancelable: true,
composed: true,
pointerId: 42,
pointerType: "pen",
clientX: 300,
clientY: 500
});
eventTarget.dispatchEvent(event1);
let pointerEventInitDict =
{
bubbles: true,
cancelable: true,
composed: true,
pointerId: 42,
pointerType: "pen",
clientX: 300,
clientY: 500,
};
const p1 = new PointerEvent("pointermove", pointerEventInitDict);
pointerEventInitDict.clientX += 10;
const p2 = new PointerEvent("pointermove", pointerEventInitDict);
pointerEventInitDict.coalescedEvents = [p1, p2];
const event2 = new PointerEvent("pointermove", pointerEventInitDict);
eventTarget.dispatchEvent(event2);</code>
</pre>
</section>
<section>
<h1>Pointer Events and interfaces</h1>
<section>
<h2><code>PointerEvent</code> interface</h2>
<div>
<pre class="idl">
dictionary PointerEventInit : MouseEventInit {
long pointerId = 0;
double width = 1;
double height = 1;
float pressure = 0;
float tangentialPressure = 0;
long tiltX;
long tiltY;
long twist = 0;
double altitudeAngle;
double azimuthAngle;
DOMString pointerType = "";
boolean isPrimary = false;
sequence<PointerEvent> coalescedEvents = [];
sequence<PointerEvent> predictedEvents = [];
};
[Exposed=Window]
interface PointerEvent : MouseEvent {
constructor(DOMString type, optional PointerEventInit eventInitDict = {});
readonly attribute long pointerId;
readonly attribute double width;
readonly attribute double height;
readonly attribute float pressure;
readonly attribute float tangentialPressure;
readonly attribute long tiltX;
readonly attribute long tiltY;
readonly attribute long twist;
readonly attribute double altitudeAngle;
readonly attribute double azimuthAngle;
readonly attribute DOMString pointerType;
readonly attribute boolean isPrimary;
[SecureContext] sequence<PointerEvent> getCoalescedEvents();
sequence<PointerEvent> getPredictedEvents();
};
</pre>
<dl data-dfn-for="PointerEvent" data-link-for="PointerEvent">
<dt><dfn>pointerId</dfn></dt>
<dd>
<p>A unique identifier for the pointer causing the event. User agents MAY reserve a generic <code>pointerId</code> value of <code>0</code> or <code>1</code> for the primary mouse pointer. The <code>pointerId</code> value of <code>-1</code> MUST be reserved and used to indicate events that were generated by something other than a pointing device. For any other pointers, user agents are free to implement different strategies and approaches in how they assign a <code>pointerId</code> value. However, all <a data-lt="active pointer">active pointers</a> in the [=top-level browsing context=] (as defined by [[HTML]]) must be unique, and the identifier MUST NOT be influenced by any other top-level browsing context (i.e. one top-level browsing context cannot assume that the <code>pointerId</code> of a pointer will be the same when the pointer moves outside of the browsing context and into another top-level browsing context). The user agent MAY recycle previously retired values for <code>pointerId</code> from previous active pointers, or it MAY always reuse the same <code>pointerId</code> for a particular pointing device (for instance, to uniquely identify particular pen/stylus inputs from a specific user in a multi-user collaborative application). However, in the latter case, to minimize the chance of fingerprinting and tracking across different pages or domains, the <code>pointerId</code> MUST only be associated explicitly with that particular pointing device for the lifetime of the page / session, and a new randomized <code>pointerId</code> MUST be chosen the next time that particular pointing device is used again in a new session.</p>
<div class="note">
<p>The <code>pointerId</code> selection algorithm is implementation specific. Therefore authors cannot assume values convey any particular meaning other than an identifier for the pointer that is unique from all other active pointers. As an example, user agents may simply assign a number, starting from <code>0</code>, to any active pointers, in the order that they become active — but these values are not guaranteed to be monotonically increasing.</p>
</div>
</dd>
<dt><dfn>width</dfn></dt>
<dd>
<p>The width (magnitude on the X axis), in CSS pixels (see [[CSS21]]), of the <a>contact geometry</a> of the pointer. This value MAY be updated on each event for a given pointer. For inputs that typically lack contact geometry (such as a traditional mouse), and in cases where the actual geometry of the input is not detected by the hardware, the <a>user agent</a> MUST return a default value of <code>1</code>>.</p>
</dd>
<dt><dfn>height</dfn></dt>
<dd>
<p>The height (magnitude on the Y axis), in CSS pixels (see [[CSS21]]), of the <a>contact geometry</a> of the pointer. This value MAY be updated on each event for a given pointer. For inputs that typically lack contact geometry (such as a traditional mouse), and in cases where the actual geometry of the input is not detected by the hardware, the <a>user agent</a> MUST return a default value of <code>1</code>.</p>
</dd>
<dt><dfn>pressure</dfn></dt>
<dd>
<p>The normalized pressure of the pointer input in the range of <code>[0,1]</code>, where <code>0</code> and <code>1</code> represent the minimum and maximum pressure the hardware is capable of detecting, respectively. For hardware and platforms that do not support pressure, the value MUST be <code>0.5</code> when in the <a>active buttons state</a> and <code>0</code> otherwise.</p>
</dd>
<dt><dfn>tangentialPressure</dfn></dt>
<dd>
<p>The normalized tangential pressure (also known as barrel pressure), typically set by an additional control (e.g. a finger wheel on an airbrush stylus), of the pointer input in the range of <code>[-1,1]</code>, where <code>0</code> is the neutral position of the control. Note that some hardware may only support positive values in the range of <code>[0,1]</code>. For hardware and platforms that do not support tangential pressure, the value MUST be <code>0</code>.</p>
<div class="note">Despite the property's name, in practice the hardware controls/sensors that generate the values for this property may not necessarily be pressure sensitive. As an example, in most cases the finger wheel on most airbrush/painting stylus implementations can be freely set, rather than requiring the user to apply a constant pressure on the wheel to prevent it from returning to the zero position.</div>
</dd>
<dt><dfn>tiltX</dfn></dt>
<dd>
<p>The plane angle (in degrees, in the range of <code>[-90,90]</code>) between the Y-Z plane and the plane containing both the transducer (e.g. pen/stylus) axis and the Y axis. A positive <code>tiltX</code> is to the right, in the direction of increasing X values. <code>tiltX</code> can be used along with <code>tiltY</code> to represent the tilt away from the normal of a transducer with the digitizer. For hardware and platforms that do not report tilt or angle, the value MUST be <code>0</code>.</p>
<figure id="figure_tiltX">
<img src="images/tiltX.png" alt="tiltX explanation diagram">
<figcaption>Positive <code>tiltX</code>.</figcaption>
</figure>
</dd>
<dt><dfn>tiltY</dfn></dt>
<dd>
<p>The plane angle (in degrees, in the range of <code>[-90,90]</code>) between the X-Z plane and the plane containing both the transducer (e.g. pen/stylus) axis and the X axis. A positive <code>tiltY</code> is towards the user, in the direction of increasing Y values. <code>tiltY</code> can be used along with <code>tiltX</code> to represent the tilt away from the normal of a transducer with the digitizer. For hardware and platforms that do not report tilt or angle, the value MUST be <code>0</code>.</p>
<figure id="figure_tiltY">
<img src="images/tiltY.png" alt="tiltY explanation diagram">
<figcaption>Positive <code>tiltY</code>.</figcaption>
</figure>
</dd>
<dt><dfn>twist</dfn></dt>
<dd>
<p>The clockwise rotation (in degrees, in the range of <code>[0,359]</code>) of a transducer (e.g. pen/stylus) around its own major axis. For hardware and platforms that do not report twist, the value MUST be <code>0</code>.</p>
</dd>
<dt><dfn>altitudeAngle</dfn></dt>
<dd>
<p>The altitude (in radians) of the transducer (e.g. pen/stylus), in the range <code>[0,π/2]</code> — where <code>0</code> is parallel to the surface (X-Y plane), and <code>π/2</code> is perpendicular to the surface. For hardware and platforms that do not report tilt or angle, the value MUST be <code>π/2</code>.</p>
<div class="note">
The default value defined here for <code>altitudeAngle</code> is <code>π/2</code>,
which positions the transducer as being perpendicular to the surface.
This differs from the <a href="https://w3c.github.io/touch-events/">Touch Events - Level 2</a> specification's
definition for the <code>altitudeAngle</code> property, which has a default value of <code>0</code>.
</div>
<figure id="figure_altitudeAngle">
<img src="images/altitudeAngle.png" alt="altitudeAngle explanation diagram">
<figcaption>Example <code>altitudeAngle</code> of <code>π/4</code> (45 degrees from the X-Y plane).</figcaption>
</figure>
</dd>
<dt><dfn>azimuthAngle</dfn></dt>
<dd>
<p>The azimuth angle (in radians) of the transducer (e.g. pen/stylus), in the range <code>[0, 2π]</code> — where <code>0</code> represents a transducer whose cap is pointing in the direction of increasing X values (point to "3 o'clock" if looking straight down) on the X-Y plane, and the values progressively increase when going clockwise (<code>π/2</code> at "6 o'clock", <code>π</code> at "9 o'clock", <code>3π/2</code> at "12 o'clock"). When the transducer is perfectly perpendicular to the surface (<code>altitudeAngle</code> of <code>π/2</code>), the value MUST be <code>0</code>. For hardware and platforms that do not report tilt or angle, the value MUST be <code>0</code>.</p>
<figure id="figure_azimuthAngle">
<img src="images/azimuthAngle.png" alt="azimuthAngle explanation diagram">
<figcaption>Example <code>azimuthAngle</code> of <code>π/6</code> ("4 o'clock").</figcaption>
</figure>
</dd>
<dt><dfn>pointerType</dfn></dt>
<dd>
<p>Indicates the device type that caused the event (mouse, pen, touch, etc.). If the user agent is to <a>fire a pointer event</a> for a mouse, pen/stylus, or touch input device, then the value of <code>pointerType</code> MUST be according to the following table:</p>
<table class="simple">
<thead>
<tr><th>Pointer Device Type</th><th><code>pointerType</code> Value</th></tr>
</thead>
<tbody>
<tr><td>Mouse</td><td><code>mouse</code></td></tr>
<tr><td>Pen / stylus</td><td><code>pen</code></td></tr>
<tr><td>Touch contact</td><td><code>touch</code></td></tr>
</tbody>
</table>
<p>If the device type cannot be detected by the user agent, then the value MUST be an empty string. If the user agent supports pointer device types other than those listed above, the value of <code>pointerType</code> SHOULD be vendor prefixed to avoid conflicting names for different types of devices. Future specifications MAY provide additional normative values for other device types.</p>
<div class="note">See <a href="#example_2" title="examples">Example 2</a> for a basic demonstration of how the <code>pointerType</code> can be used. Also note that developers should include some form of default handling to cover user agents that may have implemented their own custom <code>pointerType</code> values and for situations where <code>pointerType</code> is simply an empty string.</div>
</dd>
<dt><dfn>isPrimary</dfn></dt>
<dd>
<p>Indicates if the pointer represents the <a>primary pointer</a> of this pointer type.</p>
</dd>
<dt><dfn>getCoalescedEvents()</dfn></dt>
<dd>
<p>A method that returns the list of <a>coalesced events</a>.</p>
</dd>
<dt><dfn>getPredictedEvents()</dfn></dt>
<dd>
<p>A method that returns the list of <a>predicted events</a>.</p>
</dd>
</dl>
<p>The <dfn>PointerEventInit</dfn> dictionary is used by the {{PointerEvent}} interface's constructor to provide a mechanism by which to construct untrusted (synthetic) pointer events. It inherits from the {{MouseEventInit}} dictionary defined in [[UIEVENTS]]. See the <a href="#examples" title="examples">examples</a> for sample code demonstrating how to fire an untrusted pointer event.</p>
<p>The [=event constructing steps=] for <dfn>PointerEvent</dfn>
clones <a>PointerEventInit</a>'s <a data-lt="PointerEventInit.coalescedEvents"><code>coalescedEvents</code></a> to <a>coalesced events list</a> and
clones <a>PointerEventInit</a>'s <a data-lt="PointerEventInit.predictedEvents"><code>predictedEvents</code></a> to <a>predicted events list</a>.</p>
<div class="note">The <code>PointerEvent</code> interface inherits from {{MouseEvent}}, defined in [[[UIEVENTS]]].
Also note the proposed extension in [[[CSSOM-VIEW]]], which changes the various coordinate properties from <code>long</code>
to <code>double</code> to allow for fractional coordinates. For user agents that already implement this proposed extension for
{{PointerEvent}}, but <em>not</em> for regular {{MouseEvent}}, there are additional requirements when it comes to
the <a><code>click</code>, <code>auxclick</code>, and <code>contextmenu</code> events</a>.</div>
</div>
<section>
<h3>Button states</h3>
<section>
<h4><dfn data-lt="chorded buttons">Chorded button interactions</dfn></h4>
<p>Some pointer devices, such as mouse or pen, support multiple buttons. In the [[UIEVENTS]] Mouse Event model, each button press produces a <code>mousedown</code> and <code>mouseup</code> event. To better abstract this hardware difference and simplify cross-device input authoring, Pointer Events do not fire overlapping {{GlobalEventHandlers/pointerdown}} and {{GlobalEventHandlers/pointerup}} events for chorded button presses (depressing an additional button while another button on the pointer device is already depressed).</p>
<p>Instead, chorded button presses can be detected by inspecting changes to the <code>button</code> and <code>buttons</code> properties. The <code>button</code> and <code>buttons</code> properties are inherited from the {{MouseEvent}} interface, but with a change in semantics and values, as outlined in the following sections.</p>
<p>The modifications to the <code>button</code> and <code>buttons</code> properties apply only to pointer events. For any <a>compatibility mouse events</a> the value of <code>button</code> and <code>buttons</code> MUST follow [[UIEVENTS]].</p>
</section>
<section>
<h4>The <code>button</code> property</h4>
<p>To identify button state transitions in any pointer event (and not just {{GlobalEventHandlers/pointerdown}} and {{GlobalEventHandlers/pointerup}}), the <code>button</code> property indicates the device button whose state change fired the event.</p>
<table class="simple">
<thead><tr><th>Device Button Changes</th><th><code>button</code></th></tr></thead>
<tbody>
<tr><td>Neither buttons nor touch/pen contact changed since last event</td><td>-1</td></tr>
<tr><td>Left Mouse,<br>Touch contact,<br>Pen contact</td><td>0</td></tr>
<tr><td>Middle Mouse</td><td>1</td></tr>
<tr><td>Right Mouse,<br>Pen barrel button</td><td>2</td></tr>
<tr><td>X1 (back) Mouse</td><td>3</td></tr>
<tr><td>X2 (forward) Mouse</td><td>4</td></tr>
<tr><td>Pen eraser button</td><td>5</td></tr>
</tbody>
</table>
<div class="note">During a mouse drag, the value of the <code>button</code> property in a {{GlobalEventHandlers/pointermove}} event will be different from that in a <code>mousemove</code> event. For example, while moving the mouse with the right button pressed, the {{GlobalEventHandlers/pointermove}} events will have the <code>button</code> value -1, but the <code>mousemove</code> events will have the <code>button</code> value 2.</div>
</section>
<section>
<h4>The <code>buttons</code> property</h4>
<p>The <code>buttons</code> property gives the current state of the device buttons as a bitmask (same as in <code>MouseEvent</code>, but with an expanded set of possible values).</p>
<table class="simple">
<thead><tr><th>Current state of device buttons</th><th><code>buttons</code></th></tr></thead>
<tbody>
<tr><td><strong>Mouse moved with no buttons pressed</strong>,<br> Pen moved while hovering with no buttons pressed</td><td>0</td></tr>
<tr><td>Left Mouse,<br>Touch contact,<br>Pen contact</td><td>1</td></tr>
<tr><td>Middle Mouse</td><td>4</td></tr>
<tr><td>Right Mouse,<br>Pen barrel button</td><td>2</td></tr>
<tr><td>X1 (back) Mouse</td><td>8</td></tr>
<tr><td>X2 (forward) Mouse</td><td>16</td></tr>
<tr><td>Pen eraser button</td><td>32</td></tr>
</tbody>
</table>
</section>
</section>
<section>
<h3>The <dfn>primary pointer</dfn></h3>
<p>In a multi-pointer (e.g. multi-touch) scenario, the <code>isPrimary</code> property is used to identify a master pointer amongst the set of <a data-lt="active pointer">active pointers</a> for each pointer type.</p>
<ul>
<li>At any given time, there can only ever be at most one primary pointer for each pointer type.</li>
<li>The first pointer to become active for a particular pointer type (e.g. the first finger to touch the screen in a multi-touch interaction) becomes the primary pointer for that pointer type.</li>
<li>Only a primary pointer will produce <a>compatibility mouse events</a>. In the case where there are multiple <a>primary pointers</a>, these pointers will all produce <a>compatibility mouse events</a>.</li>
</ul>
<div class="note">Authors who desire single-pointer interaction can achieve this by ignoring non-primary pointers (however, see the note below on <a href="#multiple-primary-pointers">multiple primary pointers</a>).</div>
<div class="note" id="multiple-primary-pointers">When two or more pointer device types are being used concurrently, multiple pointers (one for each <code>pointerType</code>) are considered primary. For example, a touch contact and a mouse cursor moved simultaneously will produce pointers that are both considered primary.</div>
<div class="note">Some devices, operating systems and user agents may ignore the concurrent use of more than one type of pointer input to avoid accidental interactions. For instance, devices that support both touch and pen interactions may ignore touch inputs while the pen is actively being used, to allow users to rest their hand on the touchscreen while using the pen (a feature commonly referred to as "palm rejection"). Currently, it is not possible for authors to suppress this behavior.</div>
<div class="note">In some cases, it is possible for the user agent to fire pointer events in which no pointer is marked as a primary pointer. For instance, when there are multiple active pointers of a particular type, like a multi-touch interaction, and the primary pointer is removed (e.g. it leaves the screen), there may end up being no primary pointers. Also on platforms where the primary pointer is determined using all active pointers of the same type on the device (including those targeted at an application other than the user agent), if the first (primary) pointer is outside of the user agent and other (non-primary) pointers targeted inside the user agent, then the user agent may fire pointer events for the other pointers with a value of <code>false</code> for <code>isPrimary</code>.</div>
<div class="note" id="multiple-mouse-inputs">Current operating systems and user agents don't usually have a concept of multiple mouse inputs. When more than one mouse device is present (for instance, on a laptop with both a trackpad and an external mouse), all mouse devices are generally treated as a single device — movements on any of the devices are translated to movement of a single mouse pointer, and there is no distinction between button presses on different mouse devices. For this reason, there will usually only be a single mouse pointer, and that pointer will be primary.</div>
</section>
<section>
<h3>Firing events using the <code>PointerEvent</code> interface</h3>
<p>To <dfn>fire a pointer event</dfn> named |e| means to [=fire an event=] named |e| using <a>PointerEvent</a> whose attributes are set as defined in {{PointerEvent}} Interface and <a>Attributes and Default Actions</a>.</p>
<p>If the event is not a {{GlobalEventHandlers/gotpointercapture}}, {{GlobalEventHandlers/lostpointercapture}}, <code>click</code>, <code>auxclick</code> or <code>contextmenu</code> event, run the <a>process pending pointer capture</a> steps for this <code>PointerEvent</code>.
<p>The target object at which the event is fired is determined as follows:
<ul>
<li>If the <a>pointer capture target override</a> has been set for the pointer, set the target to <a>pointer capture target override</a> object.</li>
<li>Otherwise, set the target to the object returned by normal <a>hit test</a> mechanisms (out of scope for this specification).</li>
</ul>
<p>Let |targetDocument| be target's [=Node/node document=] [[DOM]].
<p>If the event is {{GlobalEventHandlers/pointerdown}}, {{GlobalEventHandlers/pointermove}}, or {{GlobalEventHandlers/pointerup}} set <a>active document</a> for the event's <code>pointerId</code> to |targetDocument|.</p>
<p>If the event is {{GlobalEventHandlers/pointerdown}}, the associated device is a direct manipulation device, and the target is an {{Element}},
then <a>set pointer capture</a> for this <code>pointerId</code> to the target element as described in <a>implicit pointer capture</a>.
<p>Fire the event to the determined target. The user agent SHOULD treat the target as if the pointing device has moved over it for the purpose of <a data-cite="uievents/#events-mouseevent-event-order">ensuring event ordering</a> [[UIEVENTS]].</p>
<div class="note">Using the <a>pointer capture target override</a> as the target instead of the normal hit-test result may fire some boundary events, as defined by [[UIEVENTS]]. This is the same as the pointer leaving its previous target and entering this new capturing target. When the capture is released, the same scenario may happen, as the pointer is leaving the capturing target and entering the hit-test target.</div>
<section>
<h4><dfn>Attributes and default actions</dfn></h4>
<p>The <code>bubbles</code> and <code>cancelable</code> properties and the default actions for the event types defined in this specification appear in the following table. Details of each of these event types are provided in <a>Pointer Event types</a>.</p>
<table id="pointer-event-type-table" class="simple">
<thead><tr>
<th>Event Type</th><th>Bubbles</th><th>Cancelable</th><th>Default Action</th></tr>
</thead>
<tbody>
<tr>
<td>{{GlobalEventHandlers/pointerover}}</td>
<td>Yes</td>
<td>Yes</td>
<td>None</td>
</tr>
<tr>
<td>{{GlobalEventHandlers/pointerenter}}</td>
<td>No</td>
<td>No</td>
<td>None</td>
</tr>
<tr>
<td>{{GlobalEventHandlers/pointerdown}}</td>
<td>Yes</td>
<td>Yes</td>
<td>Varies: when the pointer is primary, all default actions of the <code>mousedown</code> event
<br>Canceling this event also prevents subsequent firing of <a>compatibility mouse events</a>.</td>
</tr>
<tr>
<td>{{GlobalEventHandlers/pointermove}}</td>
<td>Yes</td>
<td>Yes</td>
<td>Varies: when the pointer is primary, all default actions of <code>mousemove</code></td>
</tr>
<tr>
<td>{{GlobalEventHandlers/pointerrawupdate}}</td>
<td>Yes</td>
<td>No</td>
<td>None</td>
</tr>
<tr>
<td>{{GlobalEventHandlers/pointerup}}</td>
<td>Yes</td>
<td>Yes</td>
<td>Varies: when the pointer is primary, all default actions of <code>mouseup</code></td>
</tr>
<tr>
<td>{{GlobalEventHandlers/pointercancel}}</td>
<td>Yes</td>
<td>No</td>
<td>None</td>
</tr>
<tr>
<td>{{GlobalEventHandlers/pointerout}}</td>
<td>Yes</td>
<td>Yes</td>
<td>None</td>
</tr>
<tr>
<td>{{GlobalEventHandlers/pointerleave}}</td>
<td>No</td>
<td>No</td>
<td>None</td>
</tr>
<tr>
<td>{{GlobalEventHandlers/gotpointercapture}}</td>
<td>Yes</td>
<td>No</td>
<td>None</td>
</tr>
<tr>
<td>{{GlobalEventHandlers/lostpointercapture}}</td>
<td>Yes</td>
<td>No</td>
<td>None</td>
</tr>
</tbody>
</table>
<p>Viewport manipulations (panning and zooming) — generally, as a result of a <a>direct manipulation</a> interaction — are intentionally NOT a default action of pointer events, meaning that these behaviors (e.g. panning a page as a result of moving a finger on a touchscreen) cannot be suppressed by canceling a pointer event. Authors must instead use <code>touch-action</code> to explicitly <a>declare the direct manipulation behavior</a> for a region of the document. Removing this dependency on the cancelation of events facilitates performance optimizations by the user agent.</p>
<p>For {{GlobalEventHandlers/pointerenter}} and {{GlobalEventHandlers/pointerleave}} events, the {{EventInit/composed}} [[DOM]] attribute SHOULD be <code>false</code>; for all other pointer events in the table above, the attribute SHOULD be <code>true</code>.</p>
<p>For all pointer events in the table above, the {{UIEvent/detail}} [[UIEVENTS]] attribute SHOULD be 0.</p>
<div class="note">Many user agents expose non-standard attributes <code>fromElement</code> and <code>toElement</code> in MouseEvents to support legacy content. We encourage those user agents to set the values of those (inherited) attributes in PointerEvents to <code>null</code> to transition authors to the use of standardized alternates (i.e. <code>target</code> and <code>relatedTarget</code>).</div>
<p>Similar to <code>MouseEvent</code> {{MouseEventInit/relatedTarget}}, the <code>relatedTarget</code> should be initialized to the element whose bounds the pointer just left (in the case of a {{GlobalEventHandlers/pointerover}} or <code>pointerenter</code> event) or the element whose bounds the pointer is entering (in the case of a {{GlobalEventHandlers/pointerout}} or {{GlobalEventHandlers/pointerleave}}). For other pointer events, this value will default to null. Note that when an element receives the pointer capture all the following events for that pointer are considered to be inside the boundary of the capturing element.</p>
<p>For {{GlobalEventHandlers/gotpointercapture}} and {{GlobalEventHandlers/lostpointercapture}} events, all the attributes except the ones defined in the table above should be the same as the Pointer Event that caused the user agent to run the <a>process pending pointer capture</a> steps and fire the {{GlobalEventHandlers/gotpointercapture}} and {{GlobalEventHandlers/lostpointercapture}} events.</p>
</section>
<section>
<h4><dfn>Process pending pointer capture</dfn></h4>
<p>The user agent MUST run the following steps when <a>implicitly releasing pointer capture</a> as well as when firing Pointer Events that are not {{GlobalEventHandlers/gotpointercapture}} or {{GlobalEventHandlers/lostpointercapture}}.</p>
<ol>
<li>If the <a>pointer capture target override</a> for this pointer is set and is not equal to the <a>pending pointer capture target override</a>, then fire a pointer event named {{GlobalEventHandlers/lostpointercapture}} at the <a>pointer capture target override</a> node.
</li>
<li>If the <a>pending pointer capture target override</a> for this pointer is set and is not equal to the <a>pointer capture target override</a>, then fire a pointer event named {{GlobalEventHandlers/gotpointercapture}} at the <a>pending pointer capture target override</a>.
</li>
<li>Set the <dfn>pointer capture target override</dfn> to the <a>pending pointer capture target override</a>, if set. Otherwise, clear the <a>pointer capture target override</a>.</li>
</ol>
<div class="note">
<p>As defined in the section for <a><code>click</code>, <code>auxclick</code>, and <code>contextmenu</code> events</a>, even after the {{GlobalEventHandlers/lostpointercapture}} event has been dispatched,
the corresponding <code>click</code>, <code>auxclick</code> or <code>contextmenu</code> event, if any, would still be dispatched to the capturing target.</p>
</div>
</section>
<section>
<h4>Suppressing a pointer event stream</h4>
<p>The user agent MUST <dfn>suppress a pointer event stream</dfn> when it detects that a pointer is unlikely to continue to produce events. Any of the following scenarios satisfy this condition (there MAY be additional scenarios):</p>
<ul>
<li>The user agent has opened a modal dialog or menu.</li>
<li>A pointer input device is physically disconnected, or a hoverable pointer input device (e.g. a hoverable pen/stylus) has left the hover range detectable by the digitizer.</li>
<li>The pointer is subsequently used by the user agent to manipulate the page viewport (e.g. panning or zooming). See the section on <a>touch-action</a> CSS property for details.
<div class="note">User agents can trigger panning or zooming through multiple pointer types (such as touch and pen), and therefore the start of a pan or zoom action may result in the suppression of various pointers, including pointers with different pointer types.</div>
</li>
<li>As part of the drag operation initiation algorithm as defined in the <a data-cite="html/#drag-and-drop-processing-model">drag and drop processing model</a> [[HTML]],
for the pointer that caused the drag operation.</li>
</ul>
<div class="note">
<p>Other scenarios in which the user agent MAY <a>suppress a pointer event stream</a> include:
<ul>
<li>A device's screen orientation is changed while a pointer is active.</li>
<li>The user attempts to interact using more simultaneous pointer inputs than the device supports.</li>
<li>The user agent interprets the input as accidental (for example, the hardware supports palm rejection).</li>
</ul>
<p>Methods for detecting any of these scenarios are out of scope for this specification.</p>
</div>
<p>The user agent MUST run the following steps to <a>suppress a pointer event stream</a>:</p>
<ul>
<li>Fire a {{GlobalEventHandlers/pointercancel}} event.</li>
<li>Fire a {{GlobalEventHandlers/pointerout}} event.</li>
<li>Fire a {{GlobalEventHandlers/pointerleave}} event.</li>
<li><a>Implicitly release the pointer capture</a> if the pointer is currently captured.</li>
</ul>
</section>
</section>
<section>
<h3>Converting between <code>tiltX</code> / <code>tiltY</code> and <code>altitudeAngle</code> / <code>azimuthAngle</code></h3>
<p>Pointer Events include two complementary sets of attributes to express the orientation of a transducer relative to the X-Y plane: <code>tiltX</code> / <code>tiltY</code> (introduced in the original Pointer Events specification), and <code>azimuthAngle</code> / <code>altitudeAngle</code> (adopted from the <a href="https://w3c.github.io/touch-events/">Touch Events - Level 2</a> specification).</p>
<p>Depending on the specific hardware and platform, user agents will likely only receive one set of values for the transducer orientation relative to the screen plane — either <code>tiltX</code> / <code>tiltY</code> or <code>altitudeAngle</code> / <code>azimuthAngle</code>. User agents MUST use the following algorithm for converting these values.</p>
<p>When the user agent calculates <code>tiltX</code> / <code>tiltY</code> from <code>azimuthAngle</code> / <code>altitudeAngle</code> it SHOULD round the final integer values using <a data-cite="ECMASCRIPT#sec-math.round">Math.round</a> [[ECMASCRIPT]] rules.</p>
<pre id="example_12" class="example" title="Converting between tiltX/tiltY and altitudeAngle/azimuthAngle"><code>/* Converting between tiltX/tiltY and altitudeAngle/azimuthAngle */
function spherical2tilt(altitudeAngle, azimuthAngle) {
const radToDeg = 180/Math.PI;
let tiltXrad = 0;
let tiltYrad = 0;
if (altitudeAngle == 0) {
// the pen is in the X-Y plane
if (azimuthAngle == 0 || azimuthAngle == 2*Math.PI) {
// pen is on positive X axis
tiltXrad = Math.PI/2;
}
if (azimuthAngle == Math.PI/2) {
// pen is on positive Y axis
tiltYrad = Math.PI/2;
}
if (azimuthAngle == Math.PI) {
// pen is on negative X axis
tiltXrad = -Math.PI/2;
}
if (azimuthAngle == 3*Math.PI/2) {
// pen is on negative Y axis
tiltYrad = -Math.PI/2;
}
if (azimuthAngle>0 && azimuthAngle<Math.PI/2) {
tiltXrad = Math.PI/2;
tiltYrad = Math.PI/2;
}
if (azimuthAngle>Math.PI/2 && azimuthAngle<Math.PI) {
tiltXrad = -Math.PI/2;
tiltYrad = Math.PI/2;
}
if (azimuthAngle>Math.PI && azimuthAngle<3*Math.PI/2) {
tiltXrad = -Math.PI/2;
tiltYrad = -Math.PI/2;
}
if (azimuthAngle>3*Math.PI/2 && azimuthAngle<2*Math.PI) {
tiltXrad = Math.PI/2;
tiltYrad = -Math.PI/2;
}
}
if (altitudeAngle != 0) {
const tanAlt = Math.tan(altitudeAngle);
tiltXrad = Math.atan(Math.cos(azimuthAngle) / tanAlt);
tiltYrad = Math.atan(Math.sin(azimuthAngle) / tanAlt);
}
return {"tiltX":tiltXrad*radToDeg, "tiltY":tiltYrad*radToDeg};
}
function tilt2spherical(tiltX, tiltY) {
const tiltXrad = tiltX * Math.PI/180;
const tiltYrad = tiltY * Math.PI/180;
// calculate azimuth angle
let azimuthAngle = 0;
if (tiltX == 0) {
if (tiltY > 0) {
azimuthAngle = Math.PI/2;
}
else if (tiltY < 0) {
azimuthAngle = 3*Math.PI/2;
}
} else if (tiltY == 0) {
if (tiltX < 0) {
azimuthAngle = Math.PI;
}
} else if (Math.abs(tiltX) == 90 || Math.abs(tiltY) == 90) {
// not enough information to calculate azimuth
azimuthAngle = 0;
} else {
// Non-boundary case: neither tiltX nor tiltY is equal to 0 or +-90
const tanX = Math.tan(tiltXrad);
const tanY = Math.tan(tiltYrad);
azimuthAngle = Math.atan2(tanY, tanX);
if (azimuthAngle < 0) {
azimuthAngle += 2*Math.PI;
}
}
// calculate altitude angle
let altitudeAngle = 0;
if (Math.abs(tiltX) == 90 || Math.abs(tiltY) == 90) {
altitudeAngle = 0
} else if (tiltX == 0) {
altitudeAngle = Math.PI/2 - Math.abs(tiltYrad);
} else if (tiltY == 0) {
altitudeAngle = Math.PI/2 - Math.abs(tiltXrad);
} else {
// Non-boundary case: neither tiltX nor tiltY is equal to 0 or +-90
altitudeAngle = Math.atan(1.0/Math.sqrt(Math.pow(Math.tan(tiltXrad),2) + Math.pow(Math.tan(tiltYrad),2)));
}
return {"altitudeAngle":altitudeAngle, "azimuthAngle":azimuthAngle};
}</code>
</pre>
</section>
</section>
<section>
<h2><dfn>Pointer Event types</dfn></h2>
<p>Below are the event types defined in this specification.</p>
<p>In the case of the <a>primary pointer</a>, these events (with the exception of {{GlobalEventHandlers/gotpointercapture}} and {{GlobalEventHandlers/lostpointercapture}}) may also fire <a>compatibility mouse events</a>.</p>
<section>
<h3>The <dfn data-dfn-for="GlobalEventHandlers" data-dfn-type="event">pointerover</dfn> event</h3>
<p>The user agent MUST <a>fire a pointer event</a> named {{GlobalEventHandlers/pointerover}} when a pointing device is moved into the <a>hit test</a> boundaries of an element. Note that <code>setPointerCapture()</code> or <code>releasePointerCapture()</code> might have changed the <a>hit test</a> target. Also note that while a pointer is captured it is considered to be always inside the boundaries of the capturing element for the purpose of firing boundary events. The user agent MUST also fire this event prior to firing a {{GlobalEventHandlers/pointerdown}} event for <a href=#mapping-for-devices-that-do-not-support-hover>devices that do not support hover</a> (see {{GlobalEventHandlers/pointerdown}}).</p>
</section>
<section>
<h3>The <dfn data-dfn-for="GlobalEventHandlers" data-dfn-type="event">pointerenter</dfn> event</h3>
<p>The user agent MUST <a>fire a pointer event</a> named {{GlobalEventHandlers/pointerenter}} when a pointing device is moved into the <a>hit test</a> boundaries of an element or one of its descendants, including as a result of a {{GlobalEventHandlers/pointerdown}} event from a device that <a href=#mapping-for-devices-that-do-not-support-hover>does not support hover</a> (see {{GlobalEventHandlers/pointerdown}}). Note that <code>setPointerCapture()</code> or <code>releasePointerCapture()</code> might have changed the <a>hit test</a> target. Also note that while a pointer is captured it is considered to be always inside the boundaries of the capturing element for the purpose of firing boundary events. This event type is similar to {{GlobalEventHandlers/pointerover}}, but differs in that it does not bubble.</p>
<div class="note">There are similarities between this event type, the <code>mouseenter</code> event described in [[UIEVENTS]], and the CSS <code>:hover</code> pseudo-class described in [[CSS21]]. See also the {{GlobalEventHandlers/pointerleave}} event.</div>
</section>
<section>
<h3>The <dfn data-dfn-for="GlobalEventHandlers" data-dfn-type="event">pointerdown</dfn> event</h3>
<p>The user agent MUST <a>fire a pointer event</a> named {{GlobalEventHandlers/pointerdown}} when a pointer enters the <a>active buttons state</a>. For mouse, this is when the device transitions from no buttons depressed to at least one button depressed. For touch, this is when physical contact is made with the <a>digitizer</a>. For pen, this is when the pen either makes physical contact with the digitizer without any button depressed, or transitions from no buttons depressed to at least one button depressed while hovering.</p>
<div class="note">For mouse (or other multi-button pointer devices), this means {{GlobalEventHandlers/pointerdown}} and {{GlobalEventHandlers/pointerup}} are not fired for all of the same circumstances as <code>mousedown</code> and <code>mouseup</code>. See <a>chorded buttons</a> for more information.</div>
<p>For input <a href=#mapping-for-devices-that-do-not-support-hover>devices that do not support hover</a>, the user agent MUST also <a>fire a pointer event</a> named {{GlobalEventHandlers/pointerover}} followed by a pointer event named {{GlobalEventHandlers/pointerenter}} prior to dispatching the {{GlobalEventHandlers/pointerdown}} event.</p>
<div class="note">Authors can prevent the firing of certain <a>compatibility mouse events</a> by canceling the {{GlobalEventHandlers/pointerdown}} event (if the <code>isPrimary</code> property is <code>true</code>). This sets the <code>PREVENT MOUSE EVENT</code> flag on the pointer. Note, however, that this does not prevent the <code>mouseover</code>, <code>mouseenter</code>, <code>mouseout</code>, or <code>mouseleave</code> events from firing.</div>
</section>
<section>
<h3>The <dfn data-dfn-for="GlobalEventHandlers" data-dfn-type="event">pointermove</dfn> event</h3>
<p>The user agent MUST <a>fire a pointer event</a> named {{GlobalEventHandlers/pointermove}} when a pointer changes any properties that don't fire
{{GlobalEventHandlers/pointerdown}} or {{GlobalEventHandlers/pointerup}} events. This includes any changes to coordinates, pressure, tangential pressure,
tilt, twist, contact geometry (i.e. <code>width</code> and <code>height</code>) or <a>chorded buttons</a>.</p>
<p>User agents MAY delay dispatch of the {{GlobalEventHandlers/pointermove}} event (for instance, for performance reasons).
The <a>coalesced events</a> information will be exposed via the <a data-lt="PointerEvent.getCoalescedEvents"><code>getCoalescedEvents()</code></a> method for the single dispatched {{GlobalEventHandlers/pointermove}} event.
The final coordinates of such events should be used for finding the target of the event.</p>
</section>
<section>
<h3>The <dfn data-dfn-for="GlobalEventHandlers" data-dfn-type="event">pointerrawupdate</dfn> event</h3>
<p>The user agent MUST <a>fire a pointer event</a>
named {{GlobalEventHandlers/pointerrawupdate}}, and only do so within a [=secure context=], when a pointer changes any properties that don't fire
<code>pointerdown</code> or <code>pointerup</code> events. See <code>pointermove</code> event for a list of such properties.</p>
<p>In contrast with {{GlobalEventHandlers/pointermove}}, user agents SHOULD dispatch {{GlobalEventHandlers/pointerrawupdate}} events as soon as possible
and as frequently as the JavaScript can handle the events.</p>
<p>The <code>target</code> of {{GlobalEventHandlers/pointerrawupdate}} events might be different from the {{GlobalEventHandlers/pointermove}} events
due to the fact that {{GlobalEventHandlers/pointermove}} events might get delayed or coalesced, and the final position of the event
which is used for finding the <code>target</code> could be different from its coalesced events.</p>
<p>Note that if there is already another {{GlobalEventHandlers/pointerrawupdate}} with the same <code>pointerId</code> that hasn't been dispatched
in the [=event loop=], the
user agent MAY coalesce the new {{GlobalEventHandlers/pointerrawupdate}} with that event instead of creating a new [=task=].
This may cause {{GlobalEventHandlers/pointerrawupdate}} to have coalesced events, and
they will all be delivered as <a>coalesced events</a> of one {{GlobalEventHandlers/pointerrawupdate}} event as soon as
the event is processed in the [=event loop=].
See <a data-lt="PointerEvent.getCoalescedEvents"><code>getCoalescedEvents()</code></a> for more information.</p>
<p>In terms of ordering of {{GlobalEventHandlers/pointerrawupdate}} and {{GlobalEventHandlers/pointermove}},
if the user agent received an update from the platform that causes both {{GlobalEventHandlers/pointerrawupdate}} and {{GlobalEventHandlers/pointermove}} events,
then the user agent MUST dispatch the {{GlobalEventHandlers/pointerrawupdate}} event before the corresponding {{GlobalEventHandlers/pointermove}}.</p>
<p>Other than the <code>target</code>, the concatenation of coalesced events lists of all dispatched {{GlobalEventHandlers/pointerrawupdate}} events
since the last {{GlobalEventHandlers/pointermove}} event is the same as the coalesced events of the next {{GlobalEventHandlers/pointermove}} event in terms of the other event attributes.
The attributes of {{GlobalEventHandlers/pointerrawupdate}} are mostly the same as {{GlobalEventHandlers/pointermove}}, with the exception of
<code>cancelable</code> which MUST be false for {{GlobalEventHandlers/pointerrawupdate}}.</p>
<p>User agents SHOULD not fire <a>compatibility mouse events</a> for {{GlobalEventHandlers/pointerrawupdate}}.</p>
<div class="note">Adding listeners for the {{GlobalEventHandlers/pointerrawupdate}} event might negatively impact the performance of the web page, depending on the implementation of the user agent.
For most use cases the other pointerevent types should suffice.
A {{GlobalEventHandlers/pointerrawupdate}} listener should only be added if JavaScript needs high frequency events and can handle them just as fast.
In these cases, there is probably no need to listen to other types of pointer events.</div>
</section>
<section>
<h3>The <dfn data-dfn-for="GlobalEventHandlers" data-event-type="event">pointerup</dfn> event</h3>
<p>The user agent MUST <a>fire a pointer event</a> named {{GlobalEventHandlers/pointerup}} when a pointer leaves the <a>active buttons state</a>. For mouse, this is when the device transitions from at least one button depressed to no buttons depressed. For touch, this is when physical contact is removed from the <a>digitizer</a>. For pen, this is when the pen is removed from the physical contact with the digitizer while no button is depressed, or transitions from at least one button depressed to no buttons depressed while hovering.</p>
<p>For input <a href=#mapping-for-devices-that-do-not-support-hover>devices that do not support hover</a>, the user agent MUST also <a>fire a pointer event</a> named {{GlobalEventHandlers/pointerout}} followed by a pointer event named {{GlobalEventHandlers/pointerleave}} after dispatching the {{GlobalEventHandlers/pointerup}} event.</p>
<p>All {{GlobalEventHandlers/pointerup}} events have a <code>pressure</code> value of <code>0</code>.
<p>The user agent MUST also <a>implicitly release the pointer capture</a> if the pointer is currently captured.</p>
<div class="note">For mouse (or other multi-button pointer devices), this means {{GlobalEventHandlers/pointerdown}} and {{GlobalEventHandlers/pointerup}} are not fired for all of the same circumstances as <code>mousedown</code> and <code>mouseup</code>. See <a>chorded buttons</a> for more information.</div>
</section>
<section>
<h3>The <dfn data-dfn-for="GlobalEventHandlers" data-dfn-type="event">pointercancel</dfn> event</h3>
<p>The user agent MUST <a>fire a pointer event</a> named {{GlobalEventHandlers/pointercancel}} when it detects a scenario to <a>suppress a pointer event stream</a>.</p>
<p>The values of the following properties of the {{GlobalEventHandlers/pointercancel}} event MUST match the values of the last dispatched pointer event with the same <code>pointerId</code>: <code>width</code>, <code>height</code>, <code>pressure</code>, <code>tangentialPressure</code>, <code>tiltX</code>, <code>tiltY</code>, <code>twist</code>, <code>altitudeAngle</code>, <code>azimuthAngle</code>, <code>pointerType</code>, <code>isPrimary</code>, and the coordinates inherited from [[UIEVENTS]]. The <code>coalescedEvents</code> and <code>predictedEvents</code> lists in the {{GlobalEventHandlers/pointercancel}} event MUST be empty, and the event's {{Event/cancelable}} attribute MUST be false.</p>
</section>
<section>
<h3>The <dfn data-dfn-for="GlobalEventHandlers" data-dfn-type="event">pointerout</dfn> event</h3>
<p>The user agent MUST <a>fire a pointer event</a> named {{GlobalEventHandlers/pointerout}} when any of the following occurs:</p>
<ul>
<li>The pointing device is moved out of the <a>hit test</a> boundaries of an element. Note that <code>setPointerCapture()</code> or <code>releasePointerCapture()</code> might have changed the <a>hit test</a> target and while a pointer is captured it is considered to be always inside the boundaries of the capturing element for the purpose of firing boundary events.</li>
<li>After firing the {{GlobalEventHandlers/pointerup}} event for a device that <a href=#mapping-for-devices-that-do-not-support-hover>does not support hover</a> (see {{GlobalEventHandlers/pointerup}}).</li>
<li>The user agent has detected a scenario to <a>suppress a pointer event stream</a>.</li>
</ul>
</section>
<section>
<h3>The <dfn data-dfn-for="GlobalEventHandlers" data-dfn-type="event">pointerleave</dfn> event</h3>
<p>The user agent MUST <a>fire a pointer event</a> named {{GlobalEventHandlers/pointerleave}} when any of the following occurs:</p>
<ul>
<li>The pointing device is moved out of the <a>hit test</a> boundaries of an element and all of its descendants. Note that <code>setPointerCapture()</code> or <code>releasePointerCapture()</code> might have changed the <a>hit test</a> target and while a pointer is captured it is considered to be always inside the boundaries of the capturing element for the purpose of firing boundary events.</li>
<li>After firing the {{GlobalEventHandlers/pointerup}} event for a device that <a href=#mapping-for-devices-that-do-not-support-hover>does not support hover</a> (see {{GlobalEventHandlers/pointerup}}).</li>
<li>The user agent has detected a scenario to <a>suppress a pointer event stream</a>.</li>
</ul>
<p>This event type is similar to {{GlobalEventHandlers/pointerout}}, but differs in that it does not bubble and that it MUST not be fired until the pointing device has left the boundaries of the element and the boundaries of all of its descendants.</p>
<div class="note">There are similarities between this event type, the <code>mouseleave</code> event described in [[UIEVENTS]], and the CSS <code>:hover</code> pseudo-class described in [[CSS21]]. See also the <code>pointerenter</code> event.</div>
</section>
<section>
<h3>The <dfn data-dfn-for="GlobalEventHandlers" data-dfn-type="event">gotpointercapture</dfn> event</h3>
<p>The user agent MUST <a>fire a pointer event</a> named {{GlobalEventHandlers/gotpointercapture}} when an element receives pointer capture. This event is fired at the element that is receiving pointer capture. Subsequent events for that pointer will be fired at this element. See the <a>setting pointer capture</a> and <a>process pending pointer capture</a> sections.</p>
</section>
<section>
<h3>The <dfn data-dfn-for="GlobalEventHandlers" data-dfn-type="event">lostpointercapture</dfn> event</h3>
<p>The user agent MUST <a>fire a pointer event</a> named {{GlobalEventHandlers/lostpointercapture}} after pointer capture is released for a pointer. This event MUST be fired prior to any subsequent events for the pointer after capture was released. This event is fired at the element from which pointer capture was removed. All subsequent events for the pointer except <a><code>click</code>, <code>auxclick</code>, and <code>contextmenu</code> events</a> follow normal hit testing mechanisms (out of scope for this specification) for determining the event target. See the <a>releasing pointer capture</a>, <a>implicit release of pointer capture</a>, and <a>process pending pointer capture</a> sections.</p>
</section>
<section>
<h3>The <dfn><code>click</code>, <code>auxclick</code>, and <code>contextmenu</code> events</dfn></h3>
<p>This section is an addition to <a data-cite="uievents/#event-type-click">click</a>,
<a data-cite="uievents/#event-type-auxclick">auxclick</a> and <a data-cite="uievents/#event-type-contextmenu">contextmenu</a>
events defined in [[UIEVENTS]]. These events are typically tied to user interface activation, and are fired even from non-pointer input devices, such as keyboards.</p>
<p>These events MUST be of type <code>PointerEvent</code>, and are subject to the additional requirements mentioned in the rest of this section.</p>
<section>
<h4>Event attributes</h4>
<p>For these events, all <code>PointerEvent</code> specific attributes (defined in this spec) other than <code>pointerId</code> and <code>pointerType</code> MUST have their default values. In addition:</p>
<ul>
<li>If the events are generated by a pointing device, their <code>pointerId</code> and <code>pointerType</code> MUST be the same as the PointerEvents that caused these events.</li>
<li>If the events are generated by a non-pointing device (such as voice recognition software or a keyboard interaction), <code>pointerId</code> MUST be <code>-1</code> and <code>pointerType</code> MUST be an empty string.</li>
</ul>
</section>
<section>
<h4>Event coordinates</h4>
<p>As noted in {{PointerEvent}}, [[[CSSOM-VIEW]]] proposes to redefine the various coordinate properties (<code>screenX</code>, <code>screenY</code>, <code>pageX</code>, <code>pageY</code>, <code>clientX</code>,
<code>clientY</code>, <code>x</code>, <code>y</code>, <code>offsetX</code>, <code>offsetY</code>) as <code>double</code>, to allow for fractional coordinates.
However, this change — when applied only to {{PointerEvent}}, but not to regular {{MouseEvent}} — has proven to lead to web compatibility issues with legacy code
in the case of <code>click</code>, <code>auxclick</code>, and <code>contextmenu</code>. For this reason, user agents that have implemented the proposed
change in [[[CSSOM-VIEW]]] only for {{PointerEvent}} MUST convert the various coordinate properties for the <code>click</code>, <code>auxclick</code>, and <code>contextmenu</code>
to <code>long</code> values (as defined in the original [[[UIEVENTS]]]) using <a data-cite="ECMASCRIPT#sec-math.floor">Math.floor</a> [[ECMASCRIPT]].</p>
</section>
<section>
<h4>Event dispatch</h4>
<p>A <code>click</code>, <code>auxclick</code> or <code>contextmenu</code> event |e| MUST follow the dispatch process defined in [[UIEVENTS]] except when <em>all</em> of the following conditions are met:</p>
<ul>
<li>event |e| is fired in response to a user interaction event |t|,</li>
<li>event |t| is a <code>PointerEvent</code>,</li>
<li>event |t| was dispatched while the corresponding pointer was captured, and</li>
<li>the capturing target of event |t| is [=connected=] [[DOM]] at the moment event |e| is being dispatched.</li>
</ul>
<p>When these conditions are met, event |e| MUST be dispatched to the capturing target of event |t|, and event |e| MUST be dispatched after the dispatch of the {{GlobalEventHandlers/lostpointercapture}} event with the same <code>pointerId</code>.</p>
<div class="note">When |t| is a <code>PointerEvent</code>, its type depends on native platform convention: if |e| is a <code>contextmenu</code> event, |t| is either a {{GlobalEventHandlers/pointerdown}} or a {{GlobalEventHandlers/pointerup}} event; if |e| is a <code>click</code> or <code>auxclick</code> event, |t| is a {{GlobalEventHandlers/pointerup}} event.</div>
</section>
</section>
</section>
</section>
<section>
<h1>Extensions to the `Element` interface</h1>
<div>
<p>The following section describes extensions to the existing {{Element}} interface to facilitate the setting and releasing of pointer capture.</p>
<pre class="idl">
partial interface Element {
undefined setPointerCapture (long pointerId);
undefined releasePointerCapture (long pointerId);
boolean hasPointerCapture (long pointerId);
};
</pre>
<dl data-dfn-for="Element" data-link-for="Element">
<dt><dfn>setPointerCapture()</dfn></dt>
<dd>
<p><a>Set pointer capture</a> for the pointer identified by the argument <code>pointerId</code> to the element on which this method is invoked. For subsequent events of the pointer, the capturing target will substitute the normal hit testing result as if the pointer is always over the capturing target, and they MUST always be targeted at this element until capture is released. The pointer MUST be in its <a>active buttons state</a> for this method to be effective, otherwise it fails silently. When the provided method's argument does not match any of the <a data-lt="active pointer">active pointers</a>, [=exception/throw=] a {{"NotFoundError"}} {{DOMException}}.</p>
</dd>
<dt><dfn>releasePointerCapture()</dfn></dt>
<dd>
<p><a>Release pointer capture</a> for the pointer identified by the argument <code>pointerId</code> from the element on which this method is invoked. Subsequent events for the pointer follow normal hit testing mechanisms (out of scope for this specification) for determining the event target. When the provided method's argument does not match any of the <a>active pointers</a>, [=exception/throw=] a {{"NotFoundError"}} {{DOMException}}.</p>
</dd>
<dt><dfn>hasPointerCapture</dfn></dt>
<dd>
<p>Indicates whether the element on which this method is invoked has <a>pointer capture</a> for the pointer identified by the argument <code>pointerId</code>. In particular, returns <code>true</code> if the <a>pending pointer capture target override</a> for <code>pointerId</code> is set to the element on which this method is invoked, and <code>false</code> otherwise.</p>
<div class="note">This method will return true immediately after a call to <a>setPointerCapture()</a>, even though that element will not yet have received a {{GlobalEventHandlers/gotpointercapture}} event. As a result it can be useful for detecting <a>implicit pointer capture</a> from inside of a {{GlobalEventHandlers/pointerdown}} event listener.</div>
</dd>
</dl>
</div>
</section>
<section>
<h1>Extensions to the `GlobalEventHandlers` mixin</h1>
<div>
<p>The following section describes extensions to the existing {{GlobalEventHandlers}} mixin to facilitate the event handler registration.</p>
<pre class="idl">
partial interface mixin GlobalEventHandlers {
attribute EventHandler onpointerover;
attribute EventHandler onpointerenter;
attribute EventHandler onpointerdown;
attribute EventHandler onpointermove;
[SecureContext] attribute EventHandler onpointerrawupdate;
attribute EventHandler onpointerup;
attribute EventHandler onpointercancel;
attribute EventHandler onpointerout;
attribute EventHandler onpointerleave;
attribute EventHandler ongotpointercapture;
attribute EventHandler onlostpointercapture;
};
</pre>
<dl data-dfn-for="GlobalEventHandlers" data-link-for="GlobalEventHandlers">
<dt><dfn>onpointerover</dfn></dt>
<dd>
The [=event handler IDL attribute=] for the {{GlobalEventHandlers/pointerover}} event type.
</dd>
<dt><dfn>onpointerenter</dfn></dt>
<dd>
The [=event handler IDL attribute=] for the <code>pointerenter</code> event type.
</dd>
<dt><dfn>onpointerdown</dfn></dt>
<dd>
The [=event handler IDL attribute=] for the {{GlobalEventHandlers/pointerdown}} event type.
</dd>
<dt><dfn>onpointermove</dfn></dt>
<dd>
The [=event handler IDL attribute=] for the {{GlobalEventHandlers/pointermove}} event type.
</dd>
<dt><dfn>onpointerrawupdate</dfn></dt>
<dd>
The [=event handler IDL attribute=] for the {{GlobalEventHandlers/pointerrawupdate}} event type.
</dd>
<dt><dfn>onpointerup</dfn></dt>
<dd>
The [=event handler IDL attribute=] for the {{GlobalEventHandlers/pointerup}} event type.
</dd>
<dt><dfn>onpointercancel</dfn></dt>
<dd>
The [=event handler IDL attribute=] for the {{GlobalEventHandlers/pointercancel}} event type.
</dd>
<dt><dfn>onpointerout</dfn></dt>
<dd>
The [=event handler IDL attribute=] for the {{GlobalEventHandlers/pointerout}} event type.
</dd>
<dt><dfn>onpointerleave</dfn></dt>
<dd>
The [=event handler IDL attribute=] for the {{GlobalEventHandlers/pointerleave}} event type.
</dd>
<dt><dfn>ongotpointercapture</dfn></dt>
<dd>
The [=event handler IDL attribute=] for the {{GlobalEventHandlers/gotpointercapture}} event type.
</dd>
<dt><dfn>onlostpointercapture</dfn></dt>
<dd>
The [=event handler IDL attribute=] for the {{GlobalEventHandlers/lostpointercapture}} event type.
</dd>
</dl>
</div>
</section>
<section>
<h1>Extensions to the `Navigator` interface</h1>
<div>
<p>The {{Navigator}} interface is defined in [[HTML]]. This specification extends the <code>Navigator</code> interface to provide device detection support.</p>
<pre class="idl">
partial interface Navigator {
readonly attribute long maxTouchPoints;
};
</pre>
<dl data-dfn-for="Navigator" data-link-for="Navigator">
<dt><dfn>maxTouchPoints</dfn></dt>
<dd><p>The maximum number of simultaneous touch contacts supported by the device. In the case of devices with multiple digitizers (e.g. multiple touchscreens), the value MUST be the maximum of the set of maximum supported contacts by each individual digitizer.</p>
<p>For example, suppose a device has 3 touchscreens, which support 2, 5, and 10 simultaneous touch contacts, respectively. The value of <code>maxTouchPoints</code> should be <code>10</code>.</p>
</dd>
</dl>
<div class="note">While a <code>maxTouchPoints</code> value of greater than <code>0</code> indicates the user's device is capable of supporting touch input, it does not necessarily mean the user <em>will</em> use touch input. Authors should be careful to also consider other input modalities that could be present on the system, such as mouse, pen, screen readers, etc.</div>
<div class="note"><code>maxTouchPoints</code> is often used to ensure that the interaction model of the content can be recognized by the current hardware. UI affordances can be provided to users with less capable hardware. On platforms where the precise number of touch points is not known, the minimum number guaranteed to be recognized is provided. Therefore, it is possible for the number of recognized touch points to exceed the value of <code>maxTouchPoints</code>.</div>
</div>
</section>
<section>
<h1><dfn data-lt="direct manipulation behavior|declare the direct manipulation behavior">Declaring direct manipulation behavior</dfn></h1>
<p>As noted in <a>Attributes and Default Actions</a>, viewport manipulations (panning and zooming) cannot be suppressed by canceling a pointer event. Instead, authors must declaratively define which of these behaviors they want to allow, and which they want to suppress, using the <code>touch-action</code> CSS property.</p>
<div class="note">While the issue of pointers used to manipulate the viewport is generally limited to touch input (where a user's finger can both interact with content and pan/zoom the page), certain user agents may also allow the same types of (direct or indirect) manipulation for other pointer types. For instance, on mobile/tablet devices, users may also be able to scroll using a stylus. While, for historical reasons, the <code>touch-action</code> CSS property defined in this specification appears to refer only to touch inputs, it does in fact apply to all forms of pointer inputs that allow <a>direct manipulation</a> for panning and zooming.</div>
<section>
<h2>The <dfn><code>touch-action</code></dfn> CSS property</h2>
<table class="simple">
<tr><th>Name:</th><td><code>touch-action</code></td></tr>
<tr><th>Value:</th><td><code>auto</code> | <code>none</code> | [ [ <code>pan-x</code> | <code>pan-left</code> | <code>pan-right</code> ] || [ <code>pan-y</code> | <code>pan-up</code> | <code>pan-down</code> ] ] | <code>manipulation</code></td></tr>
<tr><th>Initial:</th><td><code>auto</code></td></tr>
<tr><th>Applies to:</th><td>all elements except: non-replaced inline elements, table rows, row groups, table columns, and column groups.</td></tr>
<tr><th>Inherited:</th><td>no</td></tr>
<tr><th>Percentages:</th><td>N/A</td></tr>
<tr><th>Media:</th><td>visual</td></tr>
<tr><th>Computed value:</th><td>Same as specified value.</td></tr>
</table>
<p>The <code>touch-action</code> CSS property determines whether <a>direct manipulation</a> interactions (which are not limited to touch, despite the property's name) MAY trigger the user agent's panning and zooming behavior. See the section on <a><code>touch-action</code> values</a>.</p>
<p>Right before starting to pan or zoom, the user agent MUST <a>suppress a pointer event stream</a> if all of the following conditions are true:</p>
<ul>
<li>The user agent has determined (via methods out of scope for this specification) that a direct manipulation interaction is to be consumed for panning or zooming,</li>
<li>a {{GlobalEventHandlers/pointerdown}} event has been sent for the pointer, and</li>
<li>a {{GlobalEventHandlers/pointerup}} or {{GlobalEventHandlers/pointercancel}} event (following the above mentioned {{GlobalEventHandlers/pointerdown}}) has not yet been sent for the pointer.</li>
</ul>
<div class="note">Some user agents implement complex gestures for behaviors that involve a series of separate discrete gestures, but which are all treated as part of a single continuous gesture. For example, consider a "fling to scroll" gesture on a touchscreen: a user starts panning the document with a rapid finger movement, lifts the finger from the touchscreen, and the document continues panning with simulated inertia. While the document is still moving, the user may place their finger on the touchscreen and execute another "fling" to provide further momentum for the panning, or counteract the current panning to slow it down, stop panning altogether, or reverse the direction of the panning. As this specification does not normatively define how gestures and behaviors are implemented, it is left up to the user agent to decide whether or not the second touch (before it is interpreted as a second "fling" or counteraction of the current panning) fires pointer events or not.</div>
<div class="note"><code>touch-action</code> does not apply/cascade through to embedded browsing contexts. For instance, even applying <code>touch-action</code> to an <code><iframe></code> won't have any effect on the behavior of direct manipulation interactions for panning and zooming within the <code><iframe></code> itself.</div>
</section>
<section>
<h2>Determining supported direct manipulation behavior</h2>
<p>When a user interacts with an element using a <a>direct manipulation</a> pointer (such as touch or stylus on a touchscreen), the effect of that input is determined by the value of the <code>touch-action</code> property, and the default direct manipulation behaviors of the element and its ancestors, as follows:</p>
<ul>
<li>A direct manipulation interaction for panning and zooming <dfn data-lt="conforming-touch-behavior">conforms to an element's <code>touch-action</code></dfn> if the behavior is allowed in the coordinate space of the element. Note that if CSS transforms have been applied, the element's coordinate space may differ from the screen coordinate in a way that affects the conformity here; for example, the X axis of an element rotated by 90 degrees with respect to the screen will be parallel to the Y-axis of the screen coordinate.</li>
<li>A direct manipulation interaction for panning is supported if it <a data-lt="conforming-touch-behavior">conforms</a> to the <code>touch-action</code> property of each element between the hit tested element and its nearest inclusive ancestor that is a [=scroll container=] (as defined in [[CSS-OVERFLOW-3]]).</li>
<li>A direct manipulation interaction for zooming is supported if it <a data-lt="conforming-touch-behavior">conforms</a> to the <code>touch-action</code> property of each element between the hit tested element and the <code>document</code> element of the [=top-level browsing context=] (as defined in [[HTML]]).</li>
<li>Once panning or zooming has been started, and the user agent has already determined whether or not the gesture should be handled as a user agent direct manipulation behavior, any changes to the relevant <code>touch-action</code> value will be ignored for the duration of the action. For instance, programmatically changing the <code>touch-action</code> value for an element from <code>auto</code> to <code>none</code> as part of a {{GlobalEventHandlers/pointerdown}} handler script will not result in the user agent aborting or suppressing any of the pan or zoom behavior for that input for as long as that pointer is active.</li>
<li>Similarly, in the case of the various <code>touch-action</code> values of <code>pan-*</code>, once the user agent has determined whether to handle a gesture directly or not at the start of the gesture, a subsequent change in the direction of the same gesture SHOULD be ignored by the user agent for as long as that pointer is active. For instance, if an element has been set to <code>touch-action: pan-y</code> (meaning that only vertical panning is handled by the user agent), and a touch gesture starts off horizontally, no vertical panning should occur if the user changes the direction of their gesture to be vertical while their finger is still touching the screen.</li>
</ul>
<div class="note">Some user agents support panning and zooming interactions involving multiple concurrent pointers (e.g. multi-touch). Methods for processing or associating the <code>touch-action</code> values of multiple concurrent pointers is out of scope for this specification.</div>
</section>
<section>
<h2><dfn data-lt="touch-action values">Details of <code>touch-action</code> values</dfn></h2>
<p>The <code>touch-action</code> property covers direct manipulation behaviors related to viewport panning and zooming. Any additional user agent behaviors, such as text selection/highlighting, or activating links and form controls, MUST NOT be affected by this CSS property.</p>
<div class="note">The terms "panning" and "scrolling" are considered synonymous (or, more aptly, "panning" is "scrolling" using a direct manipulation input). Defining an interaction or gesture for triggering panning/scrolling, or for triggering behavior for the <code>auto</code> or <code>none</code> values, are out of scope for this specification.</div>
<dl>
<dt>auto</dt>
<dd>The user agent MAY consider any permitted direct manipulation behaviors related to panning and zooming of the viewport that begin on the element.</dd>
<dt>none</dt>
<dd>Direct manipulation interactions that begin on the element MUST NOT trigger behaviors related to viewport panning and zooming.</dd>
<dt>pan-x<br>pan-left<br>pan-right<br>pan-y<br>pan-up<br>pan-down</dt>
<dd>The user agent MAY consider direct manipulation interactions that begin on the element only for the purposes of panning that starts in any of the directions specified by all of the listed values. Once panning has started, the direction may be reversed by the user even if panning that starts in the reversed direction is disallowed. In contrast, when panning is restricted to a single axis (eg. <code>pan-y</code>), the axis cannot be changed during panning.<p>
<dt>manipulation</dt>
<dd>The user agent MAY consider direct manipulation interactions that begin on the element only for the purposes of panning and <strong>continuous</strong> zooming (such as pinch-zoom), but MUST NOT trigger other related behaviors that rely on multiple activations that must happen within a set period of time (such as double-tap to zoom, or double-tap and hold for single-finger zoom).</dd>
</dl>
<div class="note"><a data-cite="compat/#touch-action">Additional <code>touch-action</code> values</a> common in implementations are defined in [[COMPAT]].</div>
<div class="note">The <code>touch-action</code> property only applies to elements that support both the CSS <code>width</code> and <code>height</code> properties (see [[CSS21]]). This restriction is designed to facilitate user agent optimizations for <em>low-latency</em> <a>direct manipulation</a> panning and zooming. For elements not supported by default, such as <code><span></code> which is a <em>non-replaced inline element</em>, authors can set the <code>display</code> CSS property to a value, such as <code>block</code>, that supports <code>width</code> and <code>height</code>. Future specifications could extend this API to all elements.</div>
<div class="note">
<p>The direction-specific pan values are useful for customizing some overscroll behaviors.
For example, to implement a simple pull-to-refresh effect the document's <code>touch-action</code> can be set to <code>pan-x pan-down</code> whenever the scroll position is <code>0</code> and <code>pan-x pan-y</code> otherwise.
This allows pointer event handlers to define the behavior for upward panning/scrolling that start from the top of the document.</p>
<p>The direction-specific pan values can also be used for composing a component that implements custom panning with pointer event handling within an element that scrolls natively (or vice-versa).
For example, an image carousel may use <code>pan-y</code> to ensure it receives pointer events for any horizontal pan operations without interfering with vertical panning of the document.
When the carousel reaches its right-most extent, it may change its <code>touch-action</code> to <code>pan-y pan-right</code> so that a subsequent scroll operation beyond its extent can scroll the document within the viewport if possible.
It's not possible to change the behavior of a panning/scrolling operation while it is taking place.</p>
</div>
<div class="note">Disabling some default direct manipulation behaviors for panning and zooming may allow user agents to respond to other behaviors more quickly. For example, with <code>auto</code> user agents typically add 300ms of delay before <code>click</code> to allow for double-tap gestures to be handled. In these cases, explicitly setting <code>touch-action: none</code> or <code>touch-action: manipulation</code> will remove this delay. Note that the methods for determining a tap or double-tap gesture are out of scope for this specification.</div>
</section>
<pre id="example_5" class="example" title="Disallowing all direct manipulation behaviors">