Responding to Events in Dioxus

A complete guide on how to handle interactions using Dioxus Rust syntax. This covers all 93 available events, mapping each to its specific virtual DOM element and providing an independent rsx! example.

Form & Input Events

oninput

Targets: inputtextareaselect

Fires immediately as the user modifies the value. Used for controlled components.

rsx! {
    input { 
        oninput: move |event| text.set(event.value()),
        value: "{text}" 
    } 
}

onchange

Targets: inputtextareaselect

Fires when the element loses focus after its value was changed.

rsx! {
    select { 
        onchange: move |event| handle_selection(event.value()),
        option { "A" }
    } 
}

oninvalid

Targets: inputform

Fires when constraint validation fails during form submission.

rsx! {
    input { 
        required: "true",
        oninvalid: move |_| show_error.set(true)
    } 
}

onsubmit

Targets: form

Fires when a form is submitted. Always remember to call prevent_default() in web apps.

rsx! {
    form { 
        onsubmit: move |event| {
            event.prevent_default();
            send_to_api(event.values());
        },
        button { type: "submit", "Send" }
    } 
}

onreset

Targets: form

Fires when a form is visually reset.

rsx! {
    form { 
        onreset: move |_| reset_internal_state(),
        button { type: "reset", "Clear" }
    } 
}

Keyboard & Focus Events

onkeydown

Targets: inputtextareaglobal

Fires when a physical key is depressed.

rsx! {
    input { 
        onkeydown: move |event| {
            if event.key() == Key::Enter { submit() }
        }
    } 
}

onkeyup

Targets: inputglobal

Fires when a key is released.

rsx! {
    input { onkeyup: move |event| log::info!("Key released: {:?}", event.key()) } 
}

onkeypress

Targets: input

Deprecated in modern web, but supported for legacy character-producing keys.

rsx! {
    input { onkeypress: move |event| check_char(event) } 
}

onfocus

Targets: inputbuttona

Fires when an element receives focus. Does not bubble.

rsx! {
    input { onfocus: move |_| is_focused.set(true) } 
}

onblur

Targets: inputbutton

Fires when an element loses focus.

rsx! {
    input { onblur: move |_| is_focused.set(false) } 
}

onfocusin

Targets: divform

The bubbling equivalent of onfocus. Captures child focus events.

rsx! {
    form { onfocusin: move |_| highlight_form(true) } 
}

onfocusout

Targets: divform

The bubbling equivalent of onblur.

rsx! {
    form { onfocusout: move |_| highlight_form(false) } 
}

Mouse Events

onclick

Targets: buttonadiv

rsx! {
    button { onclick: move |_| count += 1, "Click Me" } 
}

oncontextmenu

Targets: global

Fires on right-click before native menus open. Use prevent_default() to render custom menus.

rsx! {
    div { 
        oncontextmenu: move |event| {
            event.prevent_default();
            open_custom_menu(event.client_coordinates());
        }
    } 
}

ondoubleclick / ondblclick

Targets: global

rsx! {
    div { ondoubleclick: move |_| like_post() } 
}

onmousedown / onmouseup

Targets: global

rsx! {
    canvas { 
        onmousedown: move |_| start_drawing(),
        onmouseup: move |_| stop_drawing()
    } 
}

onmouseenter / onmouseleave

Targets: global

Non-bubbling hover events.

rsx! {
    div { 
        onmouseenter: move |_| is_hovered.set(true),
        onmouseleave: move |_| is_hovered.set(false)
    } 
}

onmouseover / onmouseout

Targets: global

Bubbling hover events.

rsx! {
    ul { onmouseover: move |event| handle_child_hover(event) } 
}

onmousemove

Targets: global

rsx! {
    div { onmousemove: move |event| track_cursor(event.client_coordinates()) } 
}

onauxclick

Targets: global

Captures non-primary mouse buttons (like middle click).

rsx! {
    a { onauxclick: move |event| open_in_bg_tab() } 
}

Pointer & Touch Events

Unifies mouse, touch, and pen interactions into single handlers.

onpointerdown / onpointerup / onpointermove

Targets: global

rsx! {
    canvas { 
        onpointerdown: move |e| handle_contact(e),
        onpointermove: move |e| draw_stroke(e),
        onpointerup: move |e| end_contact(e)
    } 
}

onpointerenter / onpointerleave / onpointerover / onpointerout

Targets: global

rsx! {
    div { onpointerenter: move |_| show_tooltip() } 
}

onpointercancel

Targets: global

Fires when the OS interrupts the pointer (e.g., orientation change).

rsx! {
    div { onpointercancel: move |_| reset_state_machine() } 
}

ongotpointercapture / onlostpointercapture

Targets: global

rsx! {
    div { onlostpointercapture: move |_| cleanup_capture() } 
}

ontouchstart / ontouchmove / ontouchend / ontouchcancel

Targets: global

rsx! {
    div { 
        ontouchstart: move |e| calculate_pinch_zoom(e) 
    } 
}

Drag & Drop Events

ondragstart / ondrag / ondragend

Targets: Draggable elements

rsx! {
    div { 
        draggable: "true",
        ondragstart: move |event| event.data_transfer().set_data("text", "item_id"),
        ondrag: move |_| update_ghost_position(),
        ondragend: move |_| cleanup_drag()
    } 
}

ondragenter / ondragover / ondragleave / ondragexit / ondrop

Targets: Drop zones

rsx! {
    div { 
        ondragenter: move |_| highlight_zone(true),
        ondragleave: move |_| highlight_zone(false),
        ondragover: move |event| event.prevent_default(), // MUST DO THIS TO ALLOW DROP
        ondrop: move |event| process_files(event.data_transfer().files()),
        ondragexit: move |_| finalize_exit()
    } 
}

Media Lifecycle Events

onloadstart / onprogress / onloadedmetadata / onloadeddata

Targets: videoaudio

Network fetching and parsing lifecycle.

rsx! {
    video { 
        onloadstart: move |_| show_spinner(),
        onloadedmetadata: move |e| set_duration(e.duration()),
        onloadeddata: move |_| hide_spinner(),
        onprogress: move |_| update_buffer_bar()
    } 
}

oncanplay / oncanplaythrough / onwaiting / onsuspend / onstalled

Targets: videoaudio

rsx! {
    video { 
        oncanplay: move |_| enable_play_button(),
        oncanplaythrough: move |_| auto_play(),
        onwaiting: move |_| show_buffering(),
        onstalled: move |_| handle_network_error(),
        onsuspend: move |_| check_buffer_full()
    } 
}

onplay / onplaying / onpause / onended

Targets: videoaudio

rsx! {
    video { 
        onplay: move |_| set_status("Requested Play"),
        onplaying: move |_| set_status("Currently Rendering"),
        onpause: move |_| set_status("Paused"),
        onended: move |_| play_next_in_queue()
    } 
}

ontimeupdate / ondurationchange / onvolumechange

Targets: videoaudio

rsx! {
    video { 
        ontimeupdate: move |e| update_scrubber(e.current_time()),
        ondurationchange: move |e| max_time.set(e.duration()),
        onvolumechange: move |e| sync_mute_icon(e.volume())
    } 
}

onseeking / onseeked / onratechange

Targets: videoaudio

rsx! {
    video { 
        onseeking: move |_| pause_sync(),
        onseeked: move |_| resume_sync(),
        onratechange: move |e| update_speed_ui(e.playback_rate())
    } 
}

onemptied / onencrypted

Targets: videoaudio

rsx! {
    video { 
        onemptied: move |_| handle_fatal_error(),
        onencrypted: move |_| initialize_drm_workflow()
    } 
}

Layout & Scroll Events

onscroll / onscrollend / onwheel

Targets: globaloverflow-containers

rsx! {
    div { 
        onscroll: move |_| update_parallax(),
        onscrollend: move |_| snap_to_grid(),
        onwheel: move |e| map_zoom(e.delta_y())
    } 
}

onresize

Targets: global

rsx! {
    div { onresize: move |e| recalculate_canvas(e.rect()) } 
}

Clipboard & Selection Events

oncopy / oncut / onpaste

Targets: inputtextareacontenteditable

rsx! {
    div { 
        contenteditable: "true",
        oncopy: move |_| append_attribution(),
        oncut: move |_| handle_cut(),
        onpaste: move |e| strip_rich_formatting(e)
    } 
}

onselect / onselectstart / onselectionchange

Targets: inputglobal

rsx! {
    input { 
        onselect: move |_| show_formatting_tooltip(),
        onselectstart: move |_| begin_tracking(),
        onselectionchange: move |_| update_highlight()
    } 
}

oncompositionstart / oncompositionupdate / oncompositionend

Targets: input

Crucial for IME (Input Method Editor) interactions like typing CJK characters.

rsx! {
    input { 
        oncompositionstart: move |_| disable_validation(),
        oncompositionupdate: move |e| show_preview(e.data()),
        oncompositionend: move |e| commit_text(e.data())
    } 
}

Animations & Transitions

onanimationstart / onanimationiteration / onanimationend

Targets: global

rsx! {
    div { 
        class: "animate-pulse",
        onanimationstart: move |_| init_logic(),
        onanimationiteration: move |_| tick_counter(),
        onanimationend: move |_| remove_element()
    } 
}

ontransitionend

Targets: global

rsx! {
    div { ontransitionend: move |e| finalize_fade_out() } 
}

Widgets, Resources & Lifecycles

ontoggle / onbeforetoggle / oncancel

Targets: detailsdialog

rsx! {
    dialog { 
        onbeforetoggle: move |_| trigger_fade_css(),
        ontoggle: move |e| sync_state(e.new_state()),
        oncancel: move |_| handle_esc_key()
    } 
}

onload / onerror / onabort

Targets: imgiframescript

rsx! {
    img { 
        src: "profile.jpg",
        onload: move |_| reveal_image(),
        onerror: move |_| set_fallback_src(),
        onabort: move |_| log_cancellation()
    } 
}

onmounted (or onmount)

Targets: global

Fires exactly once when the element physically mounts to the underlying renderer (e.g., HTML DOM). Used to access native bounding boxes, force focus, or trigger imperative scrolling.

rsx! {
    div { 
        onmounted: move |event| async move {
            if let Ok(rect) = event.get_client_rect().await {
                setup_floating_ui(rect);
            }
        }
    } 
}

onvisible

Targets: global

An Intersection Observer hook that triggers when the element enters the visible viewport.

rsx! {
    img { 
        onvisible: move |_| fetch_high_res_image(),
        src: "placeholder.jpg"
    } 
}