UCloud logo UCloud logo UCloud
v2026.3.0
  1. UCloud/Core
  2. 1. Introduction
  3. 2. Projects
  4. 3. Accounting
  5. 4. Orchestration
  6. UCloud/IM for Slurm-based HPC
  7. 5. Installation
  8. 6. Architecture and Networking
  9. 7. User and Project Management
  10. 8. Filesystem Integration
    1. 8.1. Inter-provider file transfers
  11. 9. Slurm Integration
    1. 9.1. Application Management
    2. 9.2. Built-in Applications
  12. 10. Reference
    1. 10.1. Configuration
    2. 10.2. CLI
  13. 11. Appendix
    1. 11.1. Built-in Application Index
  14. UCloud/IM for Kubernetes
  15. 12. Installation
  16. 13. Architecture and Networking
  17. 14. Filesystem Integration
  18. 15. Compute Jobs
    1. 15.1. Public Links
    2. 15.2. Public IPs
    3. 15.3. License Servers
    4. 15.4. SSH Servers
    5. 15.5. Job Audit Log
    6. 15.6. Virtual machines
  19. 16. Integrated applications
    1. 16.1. Syncthing
    2. 16.2. Integrated terminal
  20. 17. UCX applications
    1. 17.1. Hello world
    2. 17.2. Data binding
    3. 17.3. UI events
    4. 17.4. Component reference
    5. 17.5. API reference
  21. 18. Reference
    1. 18.1. Configuration
    2. 18.2. CLI
  22. Frontend development
  23. 19. Frontend description and development guidelines
  24. Branding for UCloud
  25. 20. Branding and identity for UCloud
  26. H: Procedures
  27. 21. H: Procedures
  28. 22. H: Introduction
  29. 23. H: Auditing
  30. 24. H: Auditing scenario
  31. 25. H: GitHub actions
  32. 26. H: Deployment
  33. 27. H: 3rd party dependencies (risk assesment)
  1. Links
  2. Source Code
  3. Releases

UI events

UCX has two interaction channels:

  • Model input (OpModelInput) for bound field changes.
  • UI events (OpUiEvent) for component events such as button clicks and form submit.

Registering handlers

Attach handlers directly on nodes with .On(...):

ucx.Button("submit", "Submit", ucx.ColorPrimaryMain).
    On(ucx.UiEventClick, func(ev ucx.UiEvent) {
        app.Errors = validateState(app)
        if len(app.Errors) == 0 {
            app.SubmissionMessage = "Submission accepted"
        }
    })

Event types include:

  • ucx.UiEventClick
  • ucx.UiEventSubmit
  • ucx.UiEventChange
  • ucx.UiEventFocus
  • ucx.UiEventBlur

Reading event payloads

Event values are ucx.Value. Convert with helpers like ucx.ValueAsString(...):

ucx.ButtonEx("remove", "Remove", ucx.ColorErrorMain, ucx.IconHeroTrash, "", "./id").
    On(ucx.UiEventClick, func(ev ucx.UiEvent) {
        id := strings.TrimSpace(ucx.ValueAsString(ev.Value))
        if id == "" {
            return
        }
        removeTodoById(id)
    })

Updating model vs updating UI

In most handlers you only mutate state fields. UCX then sends a model patch automatically.

Use ucx.AppUpdateUi(app) only when the UI tree itself changed (for example component structure changes).

Common examples where AppUpdateUi(...) is needed:

  • switching between pages rendered via ucx.Router(...) + ucx.Link(...),
  • conditionally adding/removing sections,
  • changing the set of action buttons in a toolbar.

Concurrency and blocking handlers

Default .On(...) handlers are non-blocking and run in a goroutine. For long operations, keep this default and update status fields while work progresses.

If you must run synchronously, use .OnEx(..., ucx.EventHandlerBlocking, ...).

ucx.Button("syncAction", "Run", ucx.ColorWarningMain).
    OnEx(ucx.UiEventClick, ucx.EventHandlerBlocking, func(session *ucx.Session, ev ucx.UiEvent) {
        app.LastActionMessage = "Ran in blocking mode"
    })

For background tasks started outside normal handlers, manually hold app.Mutex() before mutating state and calling ucx.AppUpdateModel(app).

Previous Data binding
Next Component reference