Skip to content
Development
Skill

/makepad-2.0-events

CRITICAL: Use for Makepad 2.0 event and action handling. Triggers on: makepad event, makepad action, MatchEvent, handle_event, handle_actions, on_click, on_render, on_return, on_startup, script_eval!, script_apply_eval!, button clicked, text changed, slider changed, checkbox

From plugin
makepad-skills
74514 skills
Install
$ npx -y skills add ZhangHanDong/makepad-skills --skill makepad-2.0-events --agent claude-code

How it fires

How this skill gets triggered: by you, by Claude, or both.

  • Fires itselfAuto-invocation. Claude auto-loads it when your prompt matches the work.Auto-invocation is when the right skill fires by itself at the right moment, driven by a FLOW.md router and a hook, instead of you invoking it by name. It is the difference between a skill being installed and a skill actually getting used.Read the full definition →
  • You can call itInvoke it directly when you want it.
  • Slash command/makepad-2.0-events

Context preview

The summary Claude sees to decide when to auto-load this skill.

CRITICAL: Use for Makepad 2.0 event and action handling. Triggers on: makepad event, makepad action, MatchEvent, handle_event, handle_actions, on_click, on_render, on_return, on_startup, script_eval!, script_apply_eval!, button clicked, text changed, slider changed, checkbox

SKILL.md

makepad-2.0-events.SKILL.md
name: makepad-2.0-events
description: |
  CRITICAL: Use for Makepad 2.0 event and action handling. Triggers on:
  makepad event, makepad action, MatchEvent, handle_event, handle_actions,
  on_click, on_render, on_return, on_startup, script_eval!, script_apply_eval!,
  button clicked, text changed, slider changed, checkbox toggled,
  Hit, FingerDown, FingerUp, KeyDown, KeyUp, Focus, ids!,
  TextCopy, TextCut, SelectionHandleDrag, PopupDismissed, clipboard, selection,
  IME, ImeAction, popup window events, video inputs, camera events,
  事件, 动作, 点击, 输入, 回调, 交互, 事件处理, 剪贴板, 选择, 弹出窗口

Makepad 2.0 Event & Action System

Overview

Makepad 2.0 uses a **two-layer event system**:

1. **Splash Layer** -- Inline event handlers written directly in `script_mod!` Splash code (`on_click`, `on_render`, `on_return`, `on_startup`). These handle UI interactions declaratively inside the script, close to the widget definitions.

2. **Rust Layer** -- The `MatchEvent` trait with `handle_actions`, `handle_timer`, `handle_http_response`, etc. These handle business logic, external I/O, and anything that needs full Rust power.

Both layers communicate through two bridge macros:

  • `script_eval!(cx, { ... })` -- Execute Splash code from Rust (update state, trigger renders)
  • `script_apply_eval!(cx, widget_ref, { ... })` -- Patch widget properties from Rust at runtime

---

1. Splash Inline Event Handlers

Event handlers are attached directly to widgets inside `script_mod!` blocks. They use closure syntax with `||` for no arguments or `|arg|` for callbacks that receive a value.

on_click -- Button/widget click

Fires when the user clicks a button or clickable widget. No arguments for plain buttons, or `|checked|` for CheckBox which passes the new boolean state.

// Plain button click
add_button := Button{
    text: "Add"
    on_click: ||{
        let text = ui.todo_input.text()
        if text != "" {
            add_todo(text, "")
            ui.todo_input.set_text("")
        }
    }
}

// CheckBox click with checked state argument
check.on_click: |checked| toggle_todo(i, checked)

// Inline delete with closure capturing loop variable
delete.on_click: || delete_todo(i)

// Calling another widget's click programmatically
clear_done := ButtonFlatter{
    text: "Clear completed"
    on_click: ||{
        todos.retain(|todo| !todo.done)
        ui.todo_list.render()
    }
}

on_render -- Dynamic rendering

Fires when `.render()` is called on the target view. This is the primary mechanism for dynamic content. The body replaces the previous draw content of the view.

main_view := View{
    width: Fill
    height: Fill
    on_render: ||{
        counter_label := Label{
            text: "Count: " + state.counter
            draw_text.text_style.font_size: 24
        }
    }
}

// List rendering with for loop and per-item event handlers
todo_list := ScrollYView{
    width: Fill height: Fill
    new_batch: true
    on_render: ||{
        if todos.len() == 0
            EmptyState{}
        else for i, todo in todos {
            TodoItem{
                label.text: todo.text
                check.active: todo.done
                check.on_click: |checked| toggle_todo(i, checked)
                delete.on_click: || delete_todo(i)
            }
        }
    }
    EmptyState{}
}

**Key point**: `on_render` is NOT called automatically. You must call `ui.widget_name.render()` to trigger it. The `new_batch: true` property on a view tells the system to clear previous draw content before re-rendering.

on_return -- TextInput enter key

Fires when the user presses Enter/Return inside a TextInput. Commonly used to submit forms.

todo_input := TextInput{
    width: Fill height: 9. * theme.space_1
    empty_text: "What needs to be done?"
    on_return: || ui.add_button.on_click()
}

on_startup -- App startup

Fires once when the application starts. Defined at the `Root` level. Commonly used to trigger initial renders.

ui: Root{
    on_startup: ||{
        ui.main_view.render()
    }
    main_window := Window{
        // ...
    }
}

Event handler capabilities

Inside event handlers you can:

  • Call Splash functions: `add_todo(text, "dev")`
  • Read widget values: `let text = ui.todo_input.text()`
  • Set widget values: `ui.todo_input.set_text("")`
  • Trigger re-renders: `ui.todo_list.render()`
  • Trigger other widget clicks: `ui.add_button.on_click()`
  • Modify state variables: `state.counter += 1`
  • Use array methods: `todos.push({text: "new", done: false})`
  • Use control flow: `if text != "" { ... }`

---

2. Rust Event Handling -- MatchEvent Trait

The `MatchEvent` trait is the Rust-side event dispatcher. It receives platform events and widget actions through a set of handler methods.

Core trait definition (from `draw/src/match_event.rs`)

pub trait MatchEvent {
    // Lifecycle
    fn handle_startup(&mut self, _cx: &mut Cx) {}
    fn handle_shutdown(&mut self, _cx: &mut Cx) {}
    fn handle_foreground(&mut self, _cx: &mut Cx) {}
    fn handle_background(&mut self, _cx: &mut Cx) {}
    fn handle_pause(&mut self, _cx: &mut Cx) {}
    fn handle_resume(&mut self, _cx: &mut Cx) {}

    // Window focus
    fn handle_window_got_focus(&mut self, _cx: &mut Cx, _window_id: &WindowId) {}
    fn handle_window_lost_focus(&mut self, _cx: &mut Cx, _window_id: &WindowId) {}

    // Frame
    fn handle_next_frame(&mut self, _cx: &mut Cx, _e: &NextFrameEvent) {}

    // Widget actions (most commonly used)
    fn handle_action(&mut self, _cx: &mut Cx, _e: &Action) {}
    fn handle_actions(&mut self, cx: &mut Cx, actions: &Actions) {
        for action in actions {
            self.handle_action(cx, action);
        }
    }

    // Input
    fn handle_key_down(&mut self, _cx: &mut Cx, _e: &KeyEvent) {}
    fn handle_key_up(&mut self, _cx: &mut Cx, _e: &KeyEvent) {}
    fn handle_back_pressed(&mut self, _cx: &mut Cx) -> bool { false }

    /
Read more
Ships withmakepad-skills

Skills for building cross-platform UI applications with Makepad 2.0.

Get the whole plugin

Other skills on makepad-skills.