Compose Web HTML library for building reactive web user interfaces using Kotlin with type-safe HTML DSL, CSS styling, and event handling
—
Comprehensive event system with synthetic events that wrap native browser events while providing type safety and consistent APIs across different event types.
All events in Compose Web are synthetic events that wrap native DOM events with additional type safety and consistent behavior.
/**
* Base synthetic event interface
* @param T Native event type
*/
interface SyntheticEvent<T : Event> {
val nativeEvent: T
val target: EventTarget?
val currentTarget: EventTarget?
fun preventDefault()
fun stopPropagation()
}Mouse interaction events for clicks, movements, and button states.
/**
* Mouse event interface extending SyntheticEvent
*/
interface SyntheticMouseEvent : SyntheticEvent<MouseEvent> {
val clientX: Int
val clientY: Int
val button: Short
val buttons: Short
val altKey: Boolean
val ctrlKey: Boolean
val metaKey: Boolean
val shiftKey: Boolean
}
/**
* Mouse event listeners (available in EventsListenerScope)
*/
fun EventsListenerScope.onClick(listener: (SyntheticMouseEvent) -> Unit)
fun EventsListenerScope.onDoubleClick(listener: (SyntheticMouseEvent) -> Unit)
fun EventsListenerScope.onMouseDown(listener: (SyntheticMouseEvent) -> Unit)
fun EventsListenerScope.onMouseUp(listener: (SyntheticMouseEvent) -> Unit)
fun EventsListenerScope.onMouseEnter(listener: (SyntheticMouseEvent) -> Unit)
fun EventsListenerScope.onMouseLeave(listener: (SyntheticMouseEvent) -> Unit)
fun EventsListenerScope.onMouseMove(listener: (SyntheticMouseEvent) -> Unit)
fun EventsListenerScope.onMouseOut(listener: (SyntheticMouseEvent) -> Unit)
fun EventsListenerScope.onMouseOver(listener: (SyntheticMouseEvent) -> Unit)
fun EventsListenerScope.onWheel(listener: (SyntheticWheelEvent) -> Unit)Keyboard input events for key presses and releases.
/**
* Keyboard event interface
*/
interface SyntheticKeyboardEvent : SyntheticEvent<KeyboardEvent> {
val key: String
val code: String
val keyCode: Int
val altKey: Boolean
val ctrlKey: Boolean
val metaKey: Boolean
val shiftKey: Boolean
val repeat: Boolean
}
/**
* Keyboard event listeners
*/
fun EventsListenerScope.onKeyDown(listener: (SyntheticKeyboardEvent) -> Unit)
fun EventsListenerScope.onKeyUp(listener: (SyntheticKeyboardEvent) -> Unit)Focus and blur events for element focus state changes.
/**
* Focus event interface
*/
interface SyntheticFocusEvent : SyntheticEvent<FocusEvent> {
val relatedTarget: EventTarget?
}
/**
* Focus event listeners
*/
fun EventsListenerScope.onFocus(listener: (SyntheticFocusEvent) -> Unit)
fun EventsListenerScope.onBlur(listener: (SyntheticFocusEvent) -> Unit)
fun EventsListenerScope.onFocusIn(listener: (SyntheticFocusEvent) -> Unit)
fun EventsListenerScope.onFocusOut(listener: (SyntheticFocusEvent) -> Unit)Input value change events for form elements.
/**
* Input event interface for value changes
*/
interface SyntheticInputEvent : SyntheticEvent<InputEvent> {
val data: String?
val inputType: String
}
/**
* Change event interface for form controls
*/
interface SyntheticChangeEvent : SyntheticEvent<Event> {
val target: EventTarget?
}
/**
* Text selection event interface
*/
interface SyntheticSelectEvent : SyntheticEvent<Event>
/**
* Input event listeners
*/
fun EventsListenerScope.onInput(listener: (SyntheticInputEvent) -> Unit)
fun EventsListenerScope.onChange(listener: (SyntheticChangeEvent) -> Unit)
fun EventsListenerScope.onSelect(listener: (SyntheticSelectEvent) -> Unit)Form submission and reset events.
/**
* Form submission event interface
*/
interface SyntheticSubmitEvent : SyntheticEvent<SubmitEvent>
/**
* Form event listeners
*/
fun EventsListenerScope.onSubmit(listener: (SyntheticSubmitEvent) -> Unit)
fun EventsListenerScope.onReset(listener: (SyntheticEvent<Event>) -> Unit)Touch interaction events for mobile and touch-enabled devices.
/**
* Touch event interface
*/
interface SyntheticTouchEvent : SyntheticEvent<TouchEvent> {
val touches: TouchList
val targetTouches: TouchList
val changedTouches: TouchList
val altKey: Boolean
val ctrlKey: Boolean
val metaKey: Boolean
val shiftKey: Boolean
}
/**
* Touch event listeners
*/
fun EventsListenerScope.onTouchStart(listener: (SyntheticTouchEvent) -> Unit)
fun EventsListenerScope.onTouchEnd(listener: (SyntheticTouchEvent) -> Unit)
fun EventsListenerScope.onTouchMove(listener: (SyntheticTouchEvent) -> Unit)
fun EventsListenerScope.onTouchCancel(listener: (SyntheticTouchEvent) -> Unit)CSS animation lifecycle events.
/**
* Animation event interface for CSS animations
*/
interface SyntheticAnimationEvent : SyntheticEvent<AnimationEvent> {
val animationName: String
val elapsedTime: Double
val pseudoElement: String
}
/**
* Animation event listeners
*/
fun EventsListenerScope.onAnimationStart(listener: (SyntheticAnimationEvent) -> Unit)
fun EventsListenerScope.onAnimationEnd(listener: (SyntheticAnimationEvent) -> Unit)
fun EventsListenerScope.onAnimationIteration(listener: (SyntheticAnimationEvent) -> Unit)Clipboard operation events for copy, cut, and paste operations.
/**
* Clipboard event interface
*/
interface SyntheticClipboardEvent : SyntheticEvent<ClipboardEvent> {
val clipboardData: DataTransfer?
}
/**
* Clipboard event listeners
*/
fun EventsListenerScope.onCopy(listener: (SyntheticClipboardEvent) -> Unit)
fun EventsListenerScope.onCut(listener: (SyntheticClipboardEvent) -> Unit)
fun EventsListenerScope.onPaste(listener: (SyntheticClipboardEvent) -> Unit)Event listeners are used within the attrs builder context of HTML elements.
/**
* Event listener scope available within attrs builders
*/
interface EventsListenerScope
/**
* Attributes scope that includes event listener scope
*/
interface AttrsScope<out TElement : Element> : EventsListenerScopeUsage Examples:
import org.jetbrains.compose.web.dom.*
import org.jetbrains.compose.web.events.*
// Mouse events
Button({
onClick { event ->
console.log("Button clicked at (${event.clientX}, ${event.clientY})")
if (event.ctrlKey) {
console.log("Ctrl key was held")
}
}
onDoubleClick { event ->
console.log("Button double-clicked")
event.preventDefault()
}
}) {
Text("Click Me")
}
// Keyboard events
TextInput(value = "", {
onKeyDown { event ->
when (event.key) {
"Enter" -> {
console.log("Enter key pressed")
// Handle form submission
}
"Escape" -> {
console.log("Escape key pressed")
// Clear input or close dialog
}
else -> {
console.log("Key pressed: ${event.key}")
}
}
}
onKeyUp { event ->
if (event.ctrlKey && event.key == "z") {
console.log("Undo shortcut detected")
}
}
})
// Focus events
TextInput(value = "", {
onFocus { event ->
console.log("Input focused")
// Show help text or highlight field
}
onBlur { event ->
console.log("Input lost focus")
// Validate input or hide help text
}
})
// Input events for reactive updates
var inputValue by remember { mutableStateOf("") }
TextInput(value = inputValue, {
onInput { event ->
// Update state on every character typed
inputValue = (event.target as HTMLInputElement).value
console.log("Input value: $inputValue")
}
onChange { event ->
// Fires on blur, useful for validation
val value = (event.target as HTMLInputElement).value
console.log("Final value: $value")
}
})
// Form events
Form({
onSubmit { event ->
event.preventDefault() // Prevent default form submission
console.log("Form submitted")
// Handle form data
val formData = FormData(event.target as HTMLFormElement)
// Process form data...
}
onReset { event ->
console.log("Form reset")
// Clear custom state if needed
}
}) {
TextInput(name = "username")
PasswordInput(name = "password")
SubmitInput()
}
// Touch events for mobile
Div({
onTouchStart { event ->
console.log("Touch started with ${event.touches.length} fingers")
}
onTouchMove { event ->
event.preventDefault() // Prevent scrolling
val touch = event.touches[0]
console.log("Touch moved to (${touch.clientX}, ${touch.clientY})")
}
onTouchEnd { event ->
console.log("Touch ended")
}
}) {
Text("Touch-enabled area")
}
// Animation events
Div({
classes("animated-element")
onAnimationStart { event ->
console.log("Animation '${event.animationName}' started")
}
onAnimationEnd { event ->
console.log("Animation '${event.animationName}' completed after ${event.elapsedTime}s")
}
onAnimationIteration { event ->
console.log("Animation '${event.animationName}' iteration completed")
}
}) {
Text("Animated content")
}
// Clipboard events
TextArea({
onCopy { event ->
console.log("Text copied to clipboard")
val selectedText = window.getSelection()?.toString()
console.log("Copied text: $selectedText")
}
onPaste { event ->
val pastedData = event.clipboardData?.getData("text/plain")
console.log("Pasted text: $pastedData")
// Optionally prevent default and handle custom paste logic
// event.preventDefault()
}
})
// Event delegation example
Div({
onClick { event ->
// This will catch clicks from child elements due to event bubbling
val clickedElement = event.target as? Element
console.log("Clicked element: ${clickedElement?.tagName}")
// Stop propagation if needed
if (clickedElement?.classList?.contains("no-bubble") == true) {
event.stopPropagation()
}
}
}) {
Button { Text("Child Button 1") }
Button({ classes("no-bubble") }) { Text("Child Button 2 (no bubble)") }
P { Text("Clickable paragraph") }
}Install with Tessl CLI
npx tessl i tessl/maven-org-jetbrains-compose-html--core