CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/maven-org-jetbrains-compose-foundation--foundation-wasm-js

Compose Multiplatform foundation library for building web UIs with type-safe HTML DSL, CSS-in-Kotlin, and event handling, compiled for WebAssembly/JavaScript target

Pending
Overview
Eval results
Files

event-handling.mddocs/

Event Handling

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.

Core Imports

import org.jetbrains.compose.web.events.*
import org.jetbrains.compose.web.attributes.*
import androidx.compose.runtime.*

Capabilities

Base Event System

Core event interfaces and base functionality providing consistent event handling across all DOM events.

/**
 * Base class for all synthetic events with common properties and methods
 */
abstract class SyntheticEvent<out Element> {
    /** The element that triggered the event */
    val target: Element
    
    /** The element that the event listener is attached to */
    val currentTarget: Element
    
    /** Whether the event bubbles up the DOM tree */
    val bubbles: Boolean
    
    /** Whether the event can be cancelled */
    val cancelable: Boolean
    
    /** Whether the default action has been prevented */
    val defaultPrevented: Boolean
    
    /** The event phase (capturing, at target, bubbling) */
    val eventPhase: Short
    
    /** Whether the event is trusted (generated by user action) */
    val isTrusted: Boolean
    
    /** Timestamp when the event was created */
    val timeStamp: Double
    
    /** Event type string */
    val type: String
    
    /**
     * Prevent the default action associated with the event
     */
    fun preventDefault()
    
    /**
     * Stop the event from bubbling up the DOM tree
     */
    fun stopPropagation()
    
    /**
     * Stop the event from bubbling and prevent other listeners on the same element
     */
    fun stopImmediatePropagation()
}

/**
 * Interface for event listener registration scope
 */
interface EventsListenerScope<TElement> {
    fun addEventListener(type: String, listener: (SyntheticEvent<TElement>) -> Unit)
}

Mouse Events

Comprehensive mouse event handling with detailed position and button information.

/**
 * Mouse event with position and button details
 */
interface SyntheticMouseEvent : SyntheticEvent<Element> {
    /** Horizontal coordinate relative to the viewport */
    val clientX: Double
    
    /** Vertical coordinate relative to the viewport */
    val clientY: Double
    
    /** Horizontal coordinate relative to the entire document */
    val pageX: Double
    
    /** Vertical coordinate relative to the entire document */
    val pageY: Double
    
    /** Horizontal coordinate relative to the target element */
    val offsetX: Double
    
    /** Vertical coordinate relative to the target element */
    val offsetY: Double
    
    /** Horizontal coordinate relative to the screen */
    val screenX: Double
    
    /** Vertical coordinate relative to the screen */
    val screenY: Double
    
    /** Mouse button that was pressed (0: left, 1: middle, 2: right) */
    val button: Short
    
    /** Bitmask of all pressed mouse buttons */
    val buttons: Short
    
    /** Whether Alt key was pressed */
    val altKey: Boolean
    
    /** Whether Ctrl key was pressed */
    val ctrlKey: Boolean
    
    /** Whether Meta key was pressed (Cmd on Mac, Windows key on PC) */
    val metaKey: Boolean
    
    /** Whether Shift key was pressed */
    val shiftKey: Boolean
    
    /** Related target element (for mouseover/mouseout events) */
    val relatedTarget: Element?
}

Mouse Event Handlers:

/**
 * Click event (mouse button press and release)
 */
fun AttrsScope<*>.onClick(listener: (SyntheticMouseEvent) -> Unit)

/**
 * Double-click event
 */
fun AttrsScope<*>.onDoubleClick(listener: (SyntheticMouseEvent) -> Unit)

/**
 * Mouse button press
 */
fun AttrsScope<*>.onMouseDown(listener: (SyntheticMouseEvent) -> Unit)

/**
 * Mouse button release
 */
fun AttrsScope<*>.onMouseUp(listener: (SyntheticMouseEvent) -> Unit)

/**
 * Mouse enters element (does not bubble)
 */
fun AttrsScope<*>.onMouseEnter(listener: (SyntheticMouseEvent) -> Unit)

/**
 * Mouse leaves element (does not bubble)
 */
fun AttrsScope<*>.onMouseLeave(listener: (SyntheticMouseEvent) -> Unit)

/**
 * Mouse enters element or its children (bubbles)
 */
fun AttrsScope<*>.onMouseOver(listener: (SyntheticMouseEvent) -> Unit)

/**
 * Mouse leaves element or its children (bubbles)
 */
fun AttrsScope<*>.onMouseOut(listener: (SyntheticMouseEvent) -> Unit)

/**
 * Mouse moves over element
 */
fun AttrsScope<*>.onMouseMove(listener: (SyntheticMouseEvent) -> Unit)

/**
 * Context menu event (right-click)
 */
fun AttrsScope<*>.onContextMenu(listener: (SyntheticMouseEvent) -> Unit)

Usage Examples:

Button({
    onClick { event ->
        console.log("Button clicked at (${event.clientX}, ${event.clientY})")
        if (event.ctrlKey) {
            console.log("Ctrl+Click detected")
        }
    }
    
    onMouseEnter { event ->
        // Change visual state on hover
        event.target.style.backgroundColor = "lightblue"
    }
    
    onMouseLeave { event ->
        // Reset visual state
        event.target.style.backgroundColor = ""
    }
}) {
    Text("Interactive Button")
}

Div({
    onMouseMove { event ->
        // Track mouse position
        updateMousePosition(event.offsetX, event.offsetY)
    }
    
    onContextMenu { event ->
        event.preventDefault() // Prevent default context menu
        showCustomContextMenu(event.clientX, event.clientY)
    }
}) {
    Text("Mouse tracking area")
}

Keyboard Events

Keyboard event handling with key identification and modifier key support.

/**
 * Keyboard event with key and modifier information
 */
interface SyntheticKeyboardEvent : SyntheticEvent<Element> {
    /** The key value (human-readable key name) */
    val key: String
    
    /** The physical key code */
    val code: String
    
    /** Legacy key code (deprecated but sometimes needed) */
    val keyCode: Int
    
    /** Whether Alt key was pressed */
    val altKey: Boolean
    
    /** Whether Ctrl key was pressed */
    val ctrlKey: Boolean
    
    /** Whether Meta key was pressed */
    val metaKey: Boolean
    
    /** Whether Shift key was pressed */
    val shiftKey: Boolean
    
    /** Whether the key is being held down (for keydown) */
    val repeat: Boolean
    
    /** Location of the key on the keyboard */
    val location: Int
}

Keyboard Event Handlers:

/**
 * Key press down
 */
fun AttrsScope<*>.onKeyDown(listener: (SyntheticKeyboardEvent) -> Unit)

/**
 * Key release
 */
fun AttrsScope<*>.onKeyUp(listener: (SyntheticKeyboardEvent) -> Unit)

/**
 * Key press (deprecated, use keydown instead)
 */
fun AttrsScope<*>.onKeyPress(listener: (SyntheticKeyboardEvent) -> Unit)

Usage Examples:

TextInput(
    value = inputValue,
    attrs = {
        onKeyDown { event ->
            when (event.key) {
                "Enter" -> {
                    if (event.ctrlKey) {
                        // Ctrl+Enter: submit form
                        submitForm()
                    } else {
                        // Enter: new line
                        handleEnterKey()
                    }
                }
                "Escape" -> {
                    // Cancel operation
                    cancelEdit()
                }
                "Tab" -> {
                    if (event.shiftKey) {
                        // Shift+Tab: previous field
                        focusPreviousField()
                    }
                    // Tab is handled by browser
                }
            }
        }
        
        onKeyUp { event ->
            // Handle key release if needed
            if (event.key == "Control") {
                hideShortcutHints()
            }
        }
    }
)

// Global keyboard shortcuts
Div({
    tabIndex(0) // Make focusable
    onKeyDown { event ->
        if (event.ctrlKey) {
            when (event.key) {
                "s" -> {
                    event.preventDefault()
                    saveDocument()
                }
                "z" -> {
                    event.preventDefault()
                    if (event.shiftKey) redo() else undo()
                }
            }
        }
    }
}) {
    // Application content
}

Focus Events

Focus and blur events for managing element focus states and accessibility.

/**
 * Focus event
 */
interface SyntheticFocusEvent : SyntheticEvent<Element> {
    /** Related target element (element losing/gaining focus) */
    val relatedTarget: Element?
}

Focus Event Handlers:

/**
 * Element gains focus
 */
fun AttrsScope<*>.onFocus(listener: (SyntheticFocusEvent) -> Unit)

/**
 * Element loses focus
 */
fun AttrsScope<*>.onBlur(listener: (SyntheticFocusEvent) -> Unit)

/**
 * Element gains focus (bubbles)
 */
fun AttrsScope<*>.onFocusIn(listener: (SyntheticFocusEvent) -> Unit)

/**
 * Element loses focus (bubbles)
 */
fun AttrsScope<*>.onFocusOut(listener: (SyntheticFocusEvent) -> Unit)

Usage Examples:

TextInput(
    value = inputValue,
    attrs = {
        onFocus { event ->
            // Highlight field on focus
            event.target.style.borderColor = "blue"
            showFieldHelp()
        }
        
        onBlur { event ->
            // Validate field on blur
            event.target.style.borderColor = ""
            validateField(inputValue)
            hideFieldHelp()
        }
    }
)

Form Events

Events specific to form elements and form interactions.

/**
 * Input event for real-time input changes
 */
interface SyntheticInputEvent : SyntheticEvent<Element> {
    /** Input value for input elements */
    val value: String
    
    /** Input data for composition events */
    val data: String?
    
    /** Input type information */
    val inputType: String
}

/**
 * Change event for input value changes (on blur/commit)
 */
interface SyntheticChangeEvent : SyntheticEvent<Element> {
    /** Changed value */
    val value: String
}

/**
 * Form submission event
 */
interface SyntheticSubmitEvent : SyntheticEvent<HTMLFormElement>

/**
 * Form reset event  
 */
interface SyntheticResetEvent : SyntheticEvent<HTMLFormElement>

Form Event Handlers:

/**
 * Input value changes (real-time)
 */
fun AttrsScope<HTMLInputElement>.onInput(listener: (SyntheticInputEvent) -> Unit)
fun AttrsScope<HTMLTextAreaElement>.onInput(listener: (SyntheticInputEvent) -> Unit)

/**
 * Input value committed (on blur or enter)
 */
fun AttrsScope<HTMLInputElement>.onChange(listener: (SyntheticChangeEvent) -> Unit)
fun AttrsScope<HTMLSelectElement>.onChange(listener: (SyntheticChangeEvent) -> Unit)

/**
 * Form submission
 */
fun AttrsScope<HTMLFormElement>.onSubmit(listener: (SyntheticSubmitEvent) -> Unit)

/**
 * Form reset
 */
fun AttrsScope<HTMLFormElement>.onReset(listener: (SyntheticResetEvent) -> Unit)

/**
 * Invalid input (validation failure)
 */
fun AttrsScope<HTMLInputElement>.onInvalid(listener: (SyntheticEvent<HTMLInputElement>) -> Unit)

Usage Examples:

Form({
    onSubmit { event ->
        event.preventDefault() // Prevent default form submission
        
        if (validateForm()) {
            submitFormData()
        }
    }
    
    onReset { event ->
        resetFormState()
    }
}) {
    TextInput(
        value = emailValue,
        attrs = {
            type(InputType.Email)
            required()
            
            onInput { event ->
                // Real-time validation
                emailValue = event.value
                validateEmail(event.value)
            }
            
            onChange { event ->
                // Final validation on commit
                if (event.value.isNotEmpty()) {
                    checkEmailAvailability(event.value)
                }
            }
            
            onInvalid { event ->
                // Handle validation failure
                showValidationError("Please enter a valid email")
            }
        }
    )
}

Touch Events

Touch event handling for mobile and touch-enabled devices.

/**
 * Touch event with touch point information
 */
interface SyntheticTouchEvent : SyntheticEvent<Element> {
    /** List of all touch points */
    val touches: TouchList
    
    /** List of touch points that changed */
    val changedTouches: TouchList
    
    /** List of touch points on the current target */
    val targetTouches: TouchList
    
    /** Whether Alt key was pressed */
    val altKey: Boolean
    
    /** Whether Ctrl key was pressed */
    val ctrlKey: Boolean
    
    /** Whether Meta key was pressed */
    val metaKey: Boolean
    
    /** Whether Shift key was pressed */
    val shiftKey: Boolean
}

/**
 * Individual touch point
 */
interface Touch {
    /** Unique identifier for the touch */
    val identifier: Int
    
    /** Target element */
    val target: Element
    
    /** Touch coordinates */
    val clientX: Double
    val clientY: Double
    val pageX: Double
    val pageY: Double
    val screenX: Double
    val screenY: Double
    
    /** Touch area */
    val radiusX: Double
    val radiusY: Double
    
    /** Touch pressure */
    val force: Double
}

Touch Event Handlers:

/**
 * Touch starts
 */
fun AttrsScope<*>.onTouchStart(listener: (SyntheticTouchEvent) -> Unit)

/**
 * Touch moves
 */
fun AttrsScope<*>.onTouchMove(listener: (SyntheticTouchEvent) -> Unit)

/**
 * Touch ends
 */
fun AttrsScope<*>.onTouchEnd(listener: (SyntheticTouchEvent) -> Unit)

/**
 * Touch cancelled
 */
fun AttrsScope<*>.onTouchCancel(listener: (SyntheticTouchEvent) -> Unit)

Clipboard Events

Clipboard operation events for copy, cut, and paste operations.

/**
 * Clipboard event
 */
interface SyntheticClipboardEvent : SyntheticEvent<Element> {
    /** Clipboard data */
    val clipboardData: DataTransfer?
}

Clipboard Event Handlers:

/**
 * Copy operation
 */
fun AttrsScope<*>.onCopy(listener: (SyntheticClipboardEvent) -> Unit)

/**
 * Cut operation
 */
fun AttrsScope<*>.onCut(listener: (SyntheticClipboardEvent) -> Unit)

/**
 * Paste operation
 */
fun AttrsScope<*>.onPaste(listener: (SyntheticClipboardEvent) -> Unit)

Animation Events

CSS animation and transition events.

/**
 * CSS animation event
 */
interface SyntheticAnimationEvent : SyntheticEvent<Element> {
    /** Animation name */
    val animationName: String
    
    /** Elapsed time */
    val elapsedTime: Double
    
    /** Pseudo element */
    val pseudoElement: String
}

/**
 * CSS transition event
 */
interface SyntheticTransitionEvent : SyntheticEvent<Element> {
    /** Property name that transitioned */
    val propertyName: String
    
    /** Elapsed time */
    val elapsedTime: Double
    
    /** Pseudo element */
    val pseudoElement: String
}

Animation Event Handlers:

/**
 * Animation starts
 */
fun AttrsScope<*>.onAnimationStart(listener: (SyntheticAnimationEvent) -> Unit)

/**
 * Animation ends
 */
fun AttrsScope<*>.onAnimationEnd(listener: (SyntheticAnimationEvent) -> Unit)

/**
 * Animation iteration
 */
fun AttrsScope<*>.onAnimationIteration(listener: (SyntheticAnimationEvent) -> Unit)

/**
 * Transition ends
 */
fun AttrsScope<*>.onTransitionEnd(listener: (SyntheticTransitionEvent) -> Unit)

Media Events

Events for audio and video elements.

/**
 * Media is ready to play
 */
fun AttrsScope<HTMLAudioElement>.onCanPlay(listener: (SyntheticEvent<HTMLAudioElement>) -> Unit)
fun AttrsScope<HTMLVideoElement>.onCanPlay(listener: (SyntheticEvent<HTMLVideoElement>) -> Unit)

/**
 * Media starts playing
 */
fun AttrsScope<HTMLAudioElement>.onPlay(listener: (SyntheticEvent<HTMLAudioElement>) -> Unit)
fun AttrsScope<HTMLVideoElement>.onPlay(listener: (SyntheticEvent<HTMLVideoElement>) -> Unit)

/**
 * Media pauses
 */
fun AttrsScope<HTMLAudioElement>.onPause(listener: (SyntheticEvent<HTMLAudioElement>) -> Unit)
fun AttrsScope<HTMLVideoElement>.onPause(listener: (SyntheticEvent<HTMLVideoElement>) -> Unit)

/**
 * Media ends
 */
fun AttrsScope<HTMLAudioElement>.onEnded(listener: (SyntheticEvent<HTMLAudioElement>) -> Unit)
fun AttrsScope<HTMLVideoElement>.onEnded(listener: (SyntheticEvent<HTMLVideoElement>) -> Unit)

/**
 * Volume changes
 */
fun AttrsScope<HTMLAudioElement>.onVolumeChange(listener: (SyntheticEvent<HTMLAudioElement>) -> Unit)
fun AttrsScope<HTMLVideoElement>.onVolumeChange(listener: (SyntheticEvent<HTMLVideoElement>) -> Unit)

Window and Document Events

Global events for window and document-level interactions.

/**
 * Window/element resize
 */
fun AttrsScope<*>.onResize(listener: (SyntheticEvent<Element>) -> Unit)

/**
 * Scroll event
 */
fun AttrsScope<*>.onScroll(listener: (SyntheticEvent<Element>) -> Unit)

/**
 * Content loaded
 */
fun AttrsScope<*>.onLoad(listener: (SyntheticEvent<Element>) -> Unit)

/**
 * Loading error
 */
fun AttrsScope<*>.onError(listener: (SyntheticEvent<Element>) -> Unit)

/**
 * Before page unload
 */
fun AttrsScope<*>.onBeforeUnload(listener: (SyntheticEvent<Element>) -> Unit)

/**
 * Page unload
 */
fun AttrsScope<*>.onUnload(listener: (SyntheticEvent<Element>) -> Unit)

Types

interface TouchList {
    val length: Int
    fun item(index: Int): Touch?
}

interface DataTransfer {
    var dropEffect: String
    var effectAllowed: String
    val files: FileList
    val items: DataTransferItemList
    val types: Array<String>
    
    fun clearData(format: String? = null)
    fun getData(format: String): String
    fun setData(format: String, data: String)
    fun setDragImage(img: Element, xOffset: Int, yOffset: Int)
}

Install with Tessl CLI

npx tessl i tessl/maven-org-jetbrains-compose-foundation--foundation-wasm-js

docs

css-styling.md

event-handling.md

form-controls.md

html-attributes.md

html-elements.md

index.md

tile.json