0
# Event Handling
1
2
Synthetic event system providing type-safe event handling for all DOM events with proper event delegation, lifecycle management, and seamless integration with Compose's reactive system.
3
4
## Core Imports
5
6
```kotlin
7
import org.jetbrains.compose.web.events.*
8
import org.jetbrains.compose.web.attributes.*
9
import androidx.compose.runtime.*
10
```
11
12
## Capabilities
13
14
### Base Event System
15
16
Core event interfaces and base functionality providing consistent event handling across all DOM events.
17
18
```kotlin { .api }
19
/**
20
* Base class for all synthetic events with common properties and methods
21
*/
22
abstract class SyntheticEvent<out Element> {
23
/** The element that triggered the event */
24
val target: Element
25
26
/** The element that the event listener is attached to */
27
val currentTarget: Element
28
29
/** Whether the event bubbles up the DOM tree */
30
val bubbles: Boolean
31
32
/** Whether the event can be cancelled */
33
val cancelable: Boolean
34
35
/** Whether the default action has been prevented */
36
val defaultPrevented: Boolean
37
38
/** The event phase (capturing, at target, bubbling) */
39
val eventPhase: Short
40
41
/** Whether the event is trusted (generated by user action) */
42
val isTrusted: Boolean
43
44
/** Timestamp when the event was created */
45
val timeStamp: Double
46
47
/** Event type string */
48
val type: String
49
50
/**
51
* Prevent the default action associated with the event
52
*/
53
fun preventDefault()
54
55
/**
56
* Stop the event from bubbling up the DOM tree
57
*/
58
fun stopPropagation()
59
60
/**
61
* Stop the event from bubbling and prevent other listeners on the same element
62
*/
63
fun stopImmediatePropagation()
64
}
65
66
/**
67
* Interface for event listener registration scope
68
*/
69
interface EventsListenerScope<TElement> {
70
fun addEventListener(type: String, listener: (SyntheticEvent<TElement>) -> Unit)
71
}
72
```
73
74
### Mouse Events
75
76
Comprehensive mouse event handling with detailed position and button information.
77
78
```kotlin { .api }
79
/**
80
* Mouse event with position and button details
81
*/
82
interface SyntheticMouseEvent : SyntheticEvent<Element> {
83
/** Horizontal coordinate relative to the viewport */
84
val clientX: Double
85
86
/** Vertical coordinate relative to the viewport */
87
val clientY: Double
88
89
/** Horizontal coordinate relative to the entire document */
90
val pageX: Double
91
92
/** Vertical coordinate relative to the entire document */
93
val pageY: Double
94
95
/** Horizontal coordinate relative to the target element */
96
val offsetX: Double
97
98
/** Vertical coordinate relative to the target element */
99
val offsetY: Double
100
101
/** Horizontal coordinate relative to the screen */
102
val screenX: Double
103
104
/** Vertical coordinate relative to the screen */
105
val screenY: Double
106
107
/** Mouse button that was pressed (0: left, 1: middle, 2: right) */
108
val button: Short
109
110
/** Bitmask of all pressed mouse buttons */
111
val buttons: Short
112
113
/** Whether Alt key was pressed */
114
val altKey: Boolean
115
116
/** Whether Ctrl key was pressed */
117
val ctrlKey: Boolean
118
119
/** Whether Meta key was pressed (Cmd on Mac, Windows key on PC) */
120
val metaKey: Boolean
121
122
/** Whether Shift key was pressed */
123
val shiftKey: Boolean
124
125
/** Related target element (for mouseover/mouseout events) */
126
val relatedTarget: Element?
127
}
128
```
129
130
**Mouse Event Handlers:**
131
132
```kotlin { .api }
133
/**
134
* Click event (mouse button press and release)
135
*/
136
fun AttrsScope<*>.onClick(listener: (SyntheticMouseEvent) -> Unit)
137
138
/**
139
* Double-click event
140
*/
141
fun AttrsScope<*>.onDoubleClick(listener: (SyntheticMouseEvent) -> Unit)
142
143
/**
144
* Mouse button press
145
*/
146
fun AttrsScope<*>.onMouseDown(listener: (SyntheticMouseEvent) -> Unit)
147
148
/**
149
* Mouse button release
150
*/
151
fun AttrsScope<*>.onMouseUp(listener: (SyntheticMouseEvent) -> Unit)
152
153
/**
154
* Mouse enters element (does not bubble)
155
*/
156
fun AttrsScope<*>.onMouseEnter(listener: (SyntheticMouseEvent) -> Unit)
157
158
/**
159
* Mouse leaves element (does not bubble)
160
*/
161
fun AttrsScope<*>.onMouseLeave(listener: (SyntheticMouseEvent) -> Unit)
162
163
/**
164
* Mouse enters element or its children (bubbles)
165
*/
166
fun AttrsScope<*>.onMouseOver(listener: (SyntheticMouseEvent) -> Unit)
167
168
/**
169
* Mouse leaves element or its children (bubbles)
170
*/
171
fun AttrsScope<*>.onMouseOut(listener: (SyntheticMouseEvent) -> Unit)
172
173
/**
174
* Mouse moves over element
175
*/
176
fun AttrsScope<*>.onMouseMove(listener: (SyntheticMouseEvent) -> Unit)
177
178
/**
179
* Context menu event (right-click)
180
*/
181
fun AttrsScope<*>.onContextMenu(listener: (SyntheticMouseEvent) -> Unit)
182
```
183
184
**Usage Examples:**
185
186
```kotlin
187
Button({
188
onClick { event ->
189
console.log("Button clicked at (${event.clientX}, ${event.clientY})")
190
if (event.ctrlKey) {
191
console.log("Ctrl+Click detected")
192
}
193
}
194
195
onMouseEnter { event ->
196
// Change visual state on hover
197
event.target.style.backgroundColor = "lightblue"
198
}
199
200
onMouseLeave { event ->
201
// Reset visual state
202
event.target.style.backgroundColor = ""
203
}
204
}) {
205
Text("Interactive Button")
206
}
207
208
Div({
209
onMouseMove { event ->
210
// Track mouse position
211
updateMousePosition(event.offsetX, event.offsetY)
212
}
213
214
onContextMenu { event ->
215
event.preventDefault() // Prevent default context menu
216
showCustomContextMenu(event.clientX, event.clientY)
217
}
218
}) {
219
Text("Mouse tracking area")
220
}
221
```
222
223
### Keyboard Events
224
225
Keyboard event handling with key identification and modifier key support.
226
227
```kotlin { .api }
228
/**
229
* Keyboard event with key and modifier information
230
*/
231
interface SyntheticKeyboardEvent : SyntheticEvent<Element> {
232
/** The key value (human-readable key name) */
233
val key: String
234
235
/** The physical key code */
236
val code: String
237
238
/** Legacy key code (deprecated but sometimes needed) */
239
val keyCode: Int
240
241
/** Whether Alt key was pressed */
242
val altKey: Boolean
243
244
/** Whether Ctrl key was pressed */
245
val ctrlKey: Boolean
246
247
/** Whether Meta key was pressed */
248
val metaKey: Boolean
249
250
/** Whether Shift key was pressed */
251
val shiftKey: Boolean
252
253
/** Whether the key is being held down (for keydown) */
254
val repeat: Boolean
255
256
/** Location of the key on the keyboard */
257
val location: Int
258
}
259
```
260
261
**Keyboard Event Handlers:**
262
263
```kotlin { .api }
264
/**
265
* Key press down
266
*/
267
fun AttrsScope<*>.onKeyDown(listener: (SyntheticKeyboardEvent) -> Unit)
268
269
/**
270
* Key release
271
*/
272
fun AttrsScope<*>.onKeyUp(listener: (SyntheticKeyboardEvent) -> Unit)
273
274
/**
275
* Key press (deprecated, use keydown instead)
276
*/
277
fun AttrsScope<*>.onKeyPress(listener: (SyntheticKeyboardEvent) -> Unit)
278
```
279
280
**Usage Examples:**
281
282
```kotlin
283
TextInput(
284
value = inputValue,
285
attrs = {
286
onKeyDown { event ->
287
when (event.key) {
288
"Enter" -> {
289
if (event.ctrlKey) {
290
// Ctrl+Enter: submit form
291
submitForm()
292
} else {
293
// Enter: new line
294
handleEnterKey()
295
}
296
}
297
"Escape" -> {
298
// Cancel operation
299
cancelEdit()
300
}
301
"Tab" -> {
302
if (event.shiftKey) {
303
// Shift+Tab: previous field
304
focusPreviousField()
305
}
306
// Tab is handled by browser
307
}
308
}
309
}
310
311
onKeyUp { event ->
312
// Handle key release if needed
313
if (event.key == "Control") {
314
hideShortcutHints()
315
}
316
}
317
}
318
)
319
320
// Global keyboard shortcuts
321
Div({
322
tabIndex(0) // Make focusable
323
onKeyDown { event ->
324
if (event.ctrlKey) {
325
when (event.key) {
326
"s" -> {
327
event.preventDefault()
328
saveDocument()
329
}
330
"z" -> {
331
event.preventDefault()
332
if (event.shiftKey) redo() else undo()
333
}
334
}
335
}
336
}
337
}) {
338
// Application content
339
}
340
```
341
342
### Focus Events
343
344
Focus and blur events for managing element focus states and accessibility.
345
346
```kotlin { .api }
347
/**
348
* Focus event
349
*/
350
interface SyntheticFocusEvent : SyntheticEvent<Element> {
351
/** Related target element (element losing/gaining focus) */
352
val relatedTarget: Element?
353
}
354
```
355
356
**Focus Event Handlers:**
357
358
```kotlin { .api }
359
/**
360
* Element gains focus
361
*/
362
fun AttrsScope<*>.onFocus(listener: (SyntheticFocusEvent) -> Unit)
363
364
/**
365
* Element loses focus
366
*/
367
fun AttrsScope<*>.onBlur(listener: (SyntheticFocusEvent) -> Unit)
368
369
/**
370
* Element gains focus (bubbles)
371
*/
372
fun AttrsScope<*>.onFocusIn(listener: (SyntheticFocusEvent) -> Unit)
373
374
/**
375
* Element loses focus (bubbles)
376
*/
377
fun AttrsScope<*>.onFocusOut(listener: (SyntheticFocusEvent) -> Unit)
378
```
379
380
**Usage Examples:**
381
382
```kotlin
383
TextInput(
384
value = inputValue,
385
attrs = {
386
onFocus { event ->
387
// Highlight field on focus
388
event.target.style.borderColor = "blue"
389
showFieldHelp()
390
}
391
392
onBlur { event ->
393
// Validate field on blur
394
event.target.style.borderColor = ""
395
validateField(inputValue)
396
hideFieldHelp()
397
}
398
}
399
)
400
```
401
402
### Form Events
403
404
Events specific to form elements and form interactions.
405
406
```kotlin { .api }
407
/**
408
* Input event for real-time input changes
409
*/
410
interface SyntheticInputEvent : SyntheticEvent<Element> {
411
/** Input value for input elements */
412
val value: String
413
414
/** Input data for composition events */
415
val data: String?
416
417
/** Input type information */
418
val inputType: String
419
}
420
421
/**
422
* Change event for input value changes (on blur/commit)
423
*/
424
interface SyntheticChangeEvent : SyntheticEvent<Element> {
425
/** Changed value */
426
val value: String
427
}
428
429
/**
430
* Form submission event
431
*/
432
interface SyntheticSubmitEvent : SyntheticEvent<HTMLFormElement>
433
434
/**
435
* Form reset event
436
*/
437
interface SyntheticResetEvent : SyntheticEvent<HTMLFormElement>
438
```
439
440
**Form Event Handlers:**
441
442
```kotlin { .api }
443
/**
444
* Input value changes (real-time)
445
*/
446
fun AttrsScope<HTMLInputElement>.onInput(listener: (SyntheticInputEvent) -> Unit)
447
fun AttrsScope<HTMLTextAreaElement>.onInput(listener: (SyntheticInputEvent) -> Unit)
448
449
/**
450
* Input value committed (on blur or enter)
451
*/
452
fun AttrsScope<HTMLInputElement>.onChange(listener: (SyntheticChangeEvent) -> Unit)
453
fun AttrsScope<HTMLSelectElement>.onChange(listener: (SyntheticChangeEvent) -> Unit)
454
455
/**
456
* Form submission
457
*/
458
fun AttrsScope<HTMLFormElement>.onSubmit(listener: (SyntheticSubmitEvent) -> Unit)
459
460
/**
461
* Form reset
462
*/
463
fun AttrsScope<HTMLFormElement>.onReset(listener: (SyntheticResetEvent) -> Unit)
464
465
/**
466
* Invalid input (validation failure)
467
*/
468
fun AttrsScope<HTMLInputElement>.onInvalid(listener: (SyntheticEvent<HTMLInputElement>) -> Unit)
469
```
470
471
**Usage Examples:**
472
473
```kotlin
474
Form({
475
onSubmit { event ->
476
event.preventDefault() // Prevent default form submission
477
478
if (validateForm()) {
479
submitFormData()
480
}
481
}
482
483
onReset { event ->
484
resetFormState()
485
}
486
}) {
487
TextInput(
488
value = emailValue,
489
attrs = {
490
type(InputType.Email)
491
required()
492
493
onInput { event ->
494
// Real-time validation
495
emailValue = event.value
496
validateEmail(event.value)
497
}
498
499
onChange { event ->
500
// Final validation on commit
501
if (event.value.isNotEmpty()) {
502
checkEmailAvailability(event.value)
503
}
504
}
505
506
onInvalid { event ->
507
// Handle validation failure
508
showValidationError("Please enter a valid email")
509
}
510
}
511
)
512
}
513
```
514
515
### Touch Events
516
517
Touch event handling for mobile and touch-enabled devices.
518
519
```kotlin { .api }
520
/**
521
* Touch event with touch point information
522
*/
523
interface SyntheticTouchEvent : SyntheticEvent<Element> {
524
/** List of all touch points */
525
val touches: TouchList
526
527
/** List of touch points that changed */
528
val changedTouches: TouchList
529
530
/** List of touch points on the current target */
531
val targetTouches: TouchList
532
533
/** Whether Alt key was pressed */
534
val altKey: Boolean
535
536
/** Whether Ctrl key was pressed */
537
val ctrlKey: Boolean
538
539
/** Whether Meta key was pressed */
540
val metaKey: Boolean
541
542
/** Whether Shift key was pressed */
543
val shiftKey: Boolean
544
}
545
546
/**
547
* Individual touch point
548
*/
549
interface Touch {
550
/** Unique identifier for the touch */
551
val identifier: Int
552
553
/** Target element */
554
val target: Element
555
556
/** Touch coordinates */
557
val clientX: Double
558
val clientY: Double
559
val pageX: Double
560
val pageY: Double
561
val screenX: Double
562
val screenY: Double
563
564
/** Touch area */
565
val radiusX: Double
566
val radiusY: Double
567
568
/** Touch pressure */
569
val force: Double
570
}
571
```
572
573
**Touch Event Handlers:**
574
575
```kotlin { .api }
576
/**
577
* Touch starts
578
*/
579
fun AttrsScope<*>.onTouchStart(listener: (SyntheticTouchEvent) -> Unit)
580
581
/**
582
* Touch moves
583
*/
584
fun AttrsScope<*>.onTouchMove(listener: (SyntheticTouchEvent) -> Unit)
585
586
/**
587
* Touch ends
588
*/
589
fun AttrsScope<*>.onTouchEnd(listener: (SyntheticTouchEvent) -> Unit)
590
591
/**
592
* Touch cancelled
593
*/
594
fun AttrsScope<*>.onTouchCancel(listener: (SyntheticTouchEvent) -> Unit)
595
```
596
597
### Clipboard Events
598
599
Clipboard operation events for copy, cut, and paste operations.
600
601
```kotlin { .api }
602
/**
603
* Clipboard event
604
*/
605
interface SyntheticClipboardEvent : SyntheticEvent<Element> {
606
/** Clipboard data */
607
val clipboardData: DataTransfer?
608
}
609
```
610
611
**Clipboard Event Handlers:**
612
613
```kotlin { .api }
614
/**
615
* Copy operation
616
*/
617
fun AttrsScope<*>.onCopy(listener: (SyntheticClipboardEvent) -> Unit)
618
619
/**
620
* Cut operation
621
*/
622
fun AttrsScope<*>.onCut(listener: (SyntheticClipboardEvent) -> Unit)
623
624
/**
625
* Paste operation
626
*/
627
fun AttrsScope<*>.onPaste(listener: (SyntheticClipboardEvent) -> Unit)
628
```
629
630
### Animation Events
631
632
CSS animation and transition events.
633
634
```kotlin { .api }
635
/**
636
* CSS animation event
637
*/
638
interface SyntheticAnimationEvent : SyntheticEvent<Element> {
639
/** Animation name */
640
val animationName: String
641
642
/** Elapsed time */
643
val elapsedTime: Double
644
645
/** Pseudo element */
646
val pseudoElement: String
647
}
648
649
/**
650
* CSS transition event
651
*/
652
interface SyntheticTransitionEvent : SyntheticEvent<Element> {
653
/** Property name that transitioned */
654
val propertyName: String
655
656
/** Elapsed time */
657
val elapsedTime: Double
658
659
/** Pseudo element */
660
val pseudoElement: String
661
}
662
```
663
664
**Animation Event Handlers:**
665
666
```kotlin { .api }
667
/**
668
* Animation starts
669
*/
670
fun AttrsScope<*>.onAnimationStart(listener: (SyntheticAnimationEvent) -> Unit)
671
672
/**
673
* Animation ends
674
*/
675
fun AttrsScope<*>.onAnimationEnd(listener: (SyntheticAnimationEvent) -> Unit)
676
677
/**
678
* Animation iteration
679
*/
680
fun AttrsScope<*>.onAnimationIteration(listener: (SyntheticAnimationEvent) -> Unit)
681
682
/**
683
* Transition ends
684
*/
685
fun AttrsScope<*>.onTransitionEnd(listener: (SyntheticTransitionEvent) -> Unit)
686
```
687
688
### Media Events
689
690
Events for audio and video elements.
691
692
```kotlin { .api }
693
/**
694
* Media is ready to play
695
*/
696
fun AttrsScope<HTMLAudioElement>.onCanPlay(listener: (SyntheticEvent<HTMLAudioElement>) -> Unit)
697
fun AttrsScope<HTMLVideoElement>.onCanPlay(listener: (SyntheticEvent<HTMLVideoElement>) -> Unit)
698
699
/**
700
* Media starts playing
701
*/
702
fun AttrsScope<HTMLAudioElement>.onPlay(listener: (SyntheticEvent<HTMLAudioElement>) -> Unit)
703
fun AttrsScope<HTMLVideoElement>.onPlay(listener: (SyntheticEvent<HTMLVideoElement>) -> Unit)
704
705
/**
706
* Media pauses
707
*/
708
fun AttrsScope<HTMLAudioElement>.onPause(listener: (SyntheticEvent<HTMLAudioElement>) -> Unit)
709
fun AttrsScope<HTMLVideoElement>.onPause(listener: (SyntheticEvent<HTMLVideoElement>) -> Unit)
710
711
/**
712
* Media ends
713
*/
714
fun AttrsScope<HTMLAudioElement>.onEnded(listener: (SyntheticEvent<HTMLAudioElement>) -> Unit)
715
fun AttrsScope<HTMLVideoElement>.onEnded(listener: (SyntheticEvent<HTMLVideoElement>) -> Unit)
716
717
/**
718
* Volume changes
719
*/
720
fun AttrsScope<HTMLAudioElement>.onVolumeChange(listener: (SyntheticEvent<HTMLAudioElement>) -> Unit)
721
fun AttrsScope<HTMLVideoElement>.onVolumeChange(listener: (SyntheticEvent<HTMLVideoElement>) -> Unit)
722
```
723
724
### Window and Document Events
725
726
Global events for window and document-level interactions.
727
728
```kotlin { .api }
729
/**
730
* Window/element resize
731
*/
732
fun AttrsScope<*>.onResize(listener: (SyntheticEvent<Element>) -> Unit)
733
734
/**
735
* Scroll event
736
*/
737
fun AttrsScope<*>.onScroll(listener: (SyntheticEvent<Element>) -> Unit)
738
739
/**
740
* Content loaded
741
*/
742
fun AttrsScope<*>.onLoad(listener: (SyntheticEvent<Element>) -> Unit)
743
744
/**
745
* Loading error
746
*/
747
fun AttrsScope<*>.onError(listener: (SyntheticEvent<Element>) -> Unit)
748
749
/**
750
* Before page unload
751
*/
752
fun AttrsScope<*>.onBeforeUnload(listener: (SyntheticEvent<Element>) -> Unit)
753
754
/**
755
* Page unload
756
*/
757
fun AttrsScope<*>.onUnload(listener: (SyntheticEvent<Element>) -> Unit)
758
```
759
760
## Types
761
762
```kotlin { .api }
763
interface TouchList {
764
val length: Int
765
fun item(index: Int): Touch?
766
}
767
768
interface DataTransfer {
769
var dropEffect: String
770
var effectAllowed: String
771
val files: FileList
772
val items: DataTransferItemList
773
val types: Array<String>
774
775
fun clearData(format: String? = null)
776
fun getData(format: String): String
777
fun setData(format: String, data: String)
778
fun setDragImage(img: Element, xOffset: Int, yOffset: Int)
779
}
780
```