0
# Event Handling
1
2
Comprehensive event system with synthetic events that wrap native browser events while providing type safety and consistent APIs across different event types.
3
4
## Capabilities
5
6
### Event System Overview
7
8
All events in Compose Web are synthetic events that wrap native DOM events with additional type safety and consistent behavior.
9
10
```kotlin { .api }
11
/**
12
* Base synthetic event interface
13
* @param T Native event type
14
*/
15
interface SyntheticEvent<T : Event> {
16
val nativeEvent: T
17
val target: EventTarget?
18
val currentTarget: EventTarget?
19
fun preventDefault()
20
fun stopPropagation()
21
}
22
```
23
24
### Mouse Events
25
26
Mouse interaction events for clicks, movements, and button states.
27
28
```kotlin { .api }
29
/**
30
* Mouse event interface extending SyntheticEvent
31
*/
32
interface SyntheticMouseEvent : SyntheticEvent<MouseEvent> {
33
val clientX: Int
34
val clientY: Int
35
val button: Short
36
val buttons: Short
37
val altKey: Boolean
38
val ctrlKey: Boolean
39
val metaKey: Boolean
40
val shiftKey: Boolean
41
}
42
43
/**
44
* Mouse event listeners (available in EventsListenerScope)
45
*/
46
fun EventsListenerScope.onClick(listener: (SyntheticMouseEvent) -> Unit)
47
fun EventsListenerScope.onDoubleClick(listener: (SyntheticMouseEvent) -> Unit)
48
fun EventsListenerScope.onMouseDown(listener: (SyntheticMouseEvent) -> Unit)
49
fun EventsListenerScope.onMouseUp(listener: (SyntheticMouseEvent) -> Unit)
50
fun EventsListenerScope.onMouseEnter(listener: (SyntheticMouseEvent) -> Unit)
51
fun EventsListenerScope.onMouseLeave(listener: (SyntheticMouseEvent) -> Unit)
52
fun EventsListenerScope.onMouseMove(listener: (SyntheticMouseEvent) -> Unit)
53
fun EventsListenerScope.onMouseOut(listener: (SyntheticMouseEvent) -> Unit)
54
fun EventsListenerScope.onMouseOver(listener: (SyntheticMouseEvent) -> Unit)
55
fun EventsListenerScope.onWheel(listener: (SyntheticWheelEvent) -> Unit)
56
```
57
58
### Keyboard Events
59
60
Keyboard input events for key presses and releases.
61
62
```kotlin { .api }
63
/**
64
* Keyboard event interface
65
*/
66
interface SyntheticKeyboardEvent : SyntheticEvent<KeyboardEvent> {
67
val key: String
68
val code: String
69
val keyCode: Int
70
val altKey: Boolean
71
val ctrlKey: Boolean
72
val metaKey: Boolean
73
val shiftKey: Boolean
74
val repeat: Boolean
75
}
76
77
/**
78
* Keyboard event listeners
79
*/
80
fun EventsListenerScope.onKeyDown(listener: (SyntheticKeyboardEvent) -> Unit)
81
fun EventsListenerScope.onKeyUp(listener: (SyntheticKeyboardEvent) -> Unit)
82
```
83
84
### Focus Events
85
86
Focus and blur events for element focus state changes.
87
88
```kotlin { .api }
89
/**
90
* Focus event interface
91
*/
92
interface SyntheticFocusEvent : SyntheticEvent<FocusEvent> {
93
val relatedTarget: EventTarget?
94
}
95
96
/**
97
* Focus event listeners
98
*/
99
fun EventsListenerScope.onFocus(listener: (SyntheticFocusEvent) -> Unit)
100
fun EventsListenerScope.onBlur(listener: (SyntheticFocusEvent) -> Unit)
101
fun EventsListenerScope.onFocusIn(listener: (SyntheticFocusEvent) -> Unit)
102
fun EventsListenerScope.onFocusOut(listener: (SyntheticFocusEvent) -> Unit)
103
```
104
105
### Input Events
106
107
Input value change events for form elements.
108
109
```kotlin { .api }
110
/**
111
* Input event interface for value changes
112
*/
113
interface SyntheticInputEvent : SyntheticEvent<InputEvent> {
114
val data: String?
115
val inputType: String
116
}
117
118
/**
119
* Change event interface for form controls
120
*/
121
interface SyntheticChangeEvent : SyntheticEvent<Event> {
122
val target: EventTarget?
123
}
124
125
/**
126
* Text selection event interface
127
*/
128
interface SyntheticSelectEvent : SyntheticEvent<Event>
129
130
/**
131
* Input event listeners
132
*/
133
fun EventsListenerScope.onInput(listener: (SyntheticInputEvent) -> Unit)
134
fun EventsListenerScope.onChange(listener: (SyntheticChangeEvent) -> Unit)
135
fun EventsListenerScope.onSelect(listener: (SyntheticSelectEvent) -> Unit)
136
```
137
138
### Form Events
139
140
Form submission and reset events.
141
142
```kotlin { .api }
143
/**
144
* Form submission event interface
145
*/
146
interface SyntheticSubmitEvent : SyntheticEvent<SubmitEvent>
147
148
/**
149
* Form event listeners
150
*/
151
fun EventsListenerScope.onSubmit(listener: (SyntheticSubmitEvent) -> Unit)
152
fun EventsListenerScope.onReset(listener: (SyntheticEvent<Event>) -> Unit)
153
```
154
155
### Touch Events
156
157
Touch interaction events for mobile and touch-enabled devices.
158
159
```kotlin { .api }
160
/**
161
* Touch event interface
162
*/
163
interface SyntheticTouchEvent : SyntheticEvent<TouchEvent> {
164
val touches: TouchList
165
val targetTouches: TouchList
166
val changedTouches: TouchList
167
val altKey: Boolean
168
val ctrlKey: Boolean
169
val metaKey: Boolean
170
val shiftKey: Boolean
171
}
172
173
/**
174
* Touch event listeners
175
*/
176
fun EventsListenerScope.onTouchStart(listener: (SyntheticTouchEvent) -> Unit)
177
fun EventsListenerScope.onTouchEnd(listener: (SyntheticTouchEvent) -> Unit)
178
fun EventsListenerScope.onTouchMove(listener: (SyntheticTouchEvent) -> Unit)
179
fun EventsListenerScope.onTouchCancel(listener: (SyntheticTouchEvent) -> Unit)
180
```
181
182
### Animation Events
183
184
CSS animation lifecycle events.
185
186
```kotlin { .api }
187
/**
188
* Animation event interface for CSS animations
189
*/
190
interface SyntheticAnimationEvent : SyntheticEvent<AnimationEvent> {
191
val animationName: String
192
val elapsedTime: Double
193
val pseudoElement: String
194
}
195
196
/**
197
* Animation event listeners
198
*/
199
fun EventsListenerScope.onAnimationStart(listener: (SyntheticAnimationEvent) -> Unit)
200
fun EventsListenerScope.onAnimationEnd(listener: (SyntheticAnimationEvent) -> Unit)
201
fun EventsListenerScope.onAnimationIteration(listener: (SyntheticAnimationEvent) -> Unit)
202
```
203
204
### Clipboard Events
205
206
Clipboard operation events for copy, cut, and paste operations.
207
208
```kotlin { .api }
209
/**
210
* Clipboard event interface
211
*/
212
interface SyntheticClipboardEvent : SyntheticEvent<ClipboardEvent> {
213
val clipboardData: DataTransfer?
214
}
215
216
/**
217
* Clipboard event listeners
218
*/
219
fun EventsListenerScope.onCopy(listener: (SyntheticClipboardEvent) -> Unit)
220
fun EventsListenerScope.onCut(listener: (SyntheticClipboardEvent) -> Unit)
221
fun EventsListenerScope.onPaste(listener: (SyntheticClipboardEvent) -> Unit)
222
```
223
224
### Event Handler Context
225
226
Event listeners are used within the attrs builder context of HTML elements.
227
228
```kotlin { .api }
229
/**
230
* Event listener scope available within attrs builders
231
*/
232
interface EventsListenerScope
233
234
/**
235
* Attributes scope that includes event listener scope
236
*/
237
interface AttrsScope<out TElement : Element> : EventsListenerScope
238
```
239
240
**Usage Examples:**
241
242
```kotlin
243
import org.jetbrains.compose.web.dom.*
244
import org.jetbrains.compose.web.events.*
245
246
// Mouse events
247
Button({
248
onClick { event ->
249
console.log("Button clicked at (${event.clientX}, ${event.clientY})")
250
if (event.ctrlKey) {
251
console.log("Ctrl key was held")
252
}
253
}
254
255
onDoubleClick { event ->
256
console.log("Button double-clicked")
257
event.preventDefault()
258
}
259
}) {
260
Text("Click Me")
261
}
262
263
// Keyboard events
264
TextInput(value = "", {
265
onKeyDown { event ->
266
when (event.key) {
267
"Enter" -> {
268
console.log("Enter key pressed")
269
// Handle form submission
270
}
271
"Escape" -> {
272
console.log("Escape key pressed")
273
// Clear input or close dialog
274
}
275
else -> {
276
console.log("Key pressed: ${event.key}")
277
}
278
}
279
}
280
281
onKeyUp { event ->
282
if (event.ctrlKey && event.key == "z") {
283
console.log("Undo shortcut detected")
284
}
285
}
286
})
287
288
// Focus events
289
TextInput(value = "", {
290
onFocus { event ->
291
console.log("Input focused")
292
// Show help text or highlight field
293
}
294
295
onBlur { event ->
296
console.log("Input lost focus")
297
// Validate input or hide help text
298
}
299
})
300
301
// Input events for reactive updates
302
var inputValue by remember { mutableStateOf("") }
303
304
TextInput(value = inputValue, {
305
onInput { event ->
306
// Update state on every character typed
307
inputValue = (event.target as HTMLInputElement).value
308
console.log("Input value: $inputValue")
309
}
310
311
onChange { event ->
312
// Fires on blur, useful for validation
313
val value = (event.target as HTMLInputElement).value
314
console.log("Final value: $value")
315
}
316
})
317
318
// Form events
319
Form({
320
onSubmit { event ->
321
event.preventDefault() // Prevent default form submission
322
console.log("Form submitted")
323
324
// Handle form data
325
val formData = FormData(event.target as HTMLFormElement)
326
// Process form data...
327
}
328
329
onReset { event ->
330
console.log("Form reset")
331
// Clear custom state if needed
332
}
333
}) {
334
TextInput(name = "username")
335
PasswordInput(name = "password")
336
SubmitInput()
337
}
338
339
// Touch events for mobile
340
Div({
341
onTouchStart { event ->
342
console.log("Touch started with ${event.touches.length} fingers")
343
}
344
345
onTouchMove { event ->
346
event.preventDefault() // Prevent scrolling
347
val touch = event.touches[0]
348
console.log("Touch moved to (${touch.clientX}, ${touch.clientY})")
349
}
350
351
onTouchEnd { event ->
352
console.log("Touch ended")
353
}
354
}) {
355
Text("Touch-enabled area")
356
}
357
358
// Animation events
359
Div({
360
classes("animated-element")
361
362
onAnimationStart { event ->
363
console.log("Animation '${event.animationName}' started")
364
}
365
366
onAnimationEnd { event ->
367
console.log("Animation '${event.animationName}' completed after ${event.elapsedTime}s")
368
}
369
370
onAnimationIteration { event ->
371
console.log("Animation '${event.animationName}' iteration completed")
372
}
373
}) {
374
Text("Animated content")
375
}
376
377
// Clipboard events
378
TextArea({
379
onCopy { event ->
380
console.log("Text copied to clipboard")
381
val selectedText = window.getSelection()?.toString()
382
console.log("Copied text: $selectedText")
383
}
384
385
onPaste { event ->
386
val pastedData = event.clipboardData?.getData("text/plain")
387
console.log("Pasted text: $pastedData")
388
389
// Optionally prevent default and handle custom paste logic
390
// event.preventDefault()
391
}
392
})
393
394
// Event delegation example
395
Div({
396
onClick { event ->
397
// This will catch clicks from child elements due to event bubbling
398
val clickedElement = event.target as? Element
399
console.log("Clicked element: ${clickedElement?.tagName}")
400
401
// Stop propagation if needed
402
if (clickedElement?.classList?.contains("no-bubble") == true) {
403
event.stopPropagation()
404
}
405
}
406
}) {
407
Button { Text("Child Button 1") }
408
Button({ classes("no-bubble") }) { Text("Child Button 2 (no bubble)") }
409
P { Text("Clickable paragraph") }
410
}
411
```