Skip to main content

UI Events

These events fire when Claude Code draws part of the interface, and when a person uses a control that a mod drew. The second table lists the events that the $.ui methods raise.

A deny from a hook refuses a scroll, focus, or close. An invalid tree draws the engine's own drawing.

Official pages: Draw in the Interface, Mods Reference. Source: the Mod API type file of the 2.1.312 program (schemas/claude-code.d.ts).

Example​

This hook adds a count to the spinner.

let calls = 0;
on("tool.call", ($, e, next) => {
calls += 1;
return next(e);
});
on("ui.render", { component: "Spinner" }, async ($, e, next) =>
next({
...e,
props: { ...e.props, suffix: ` · tool calls: ${calls}…` },
}),
);

Engine Events​

ItemStatusWhat it doesHow it worksWhere it can be used
ui.render
Documented: An official docs page names this item.
Fires when the engine is about to draw a component: once for each input value (props, viewport width), at plugin load, or on $.ui.invalidate("ui.render").Input RenderInput. Result RenderElement: the tree to draw. next(e) gives the engine's drawing. An invalid tree draws the engine's drawing.on('ui.render', ...). In tests: $.ui.render(...) on the test engine (not on a hook's $).
ui.resolve
Documented: An official docs page names this item.
Fires when the plugins load (not on each draw), once for each surface, component, and plugin. e names the surface and component, never the props.Input ResolveInput. Result ElementTable: the element table of the surface. A hook may restyle an element or leave one out.on('ui.resolve', ...). Also $.ui.resolve(...).
ui.press
Documented: An official docs page names this item.
Fires when a Button that a render hook drew is pressed on a surface. e is { plugin, element, component, surface }. element is the button's key. Set a key on buttons that share a label: until 2.1.304 a click was lost when same-label buttons with no key were redrawn unchanged.Input UiPressArgument. Result { element }. next(e) lets the press through. Returning { element } takes it.on('ui.press', ...).
ui.input
Documented: An official docs page names this item.
Fires when an Input that a render hook drew changes or the person submits it. e is { plugin, element, component, surface, kind, value }.Input UiInputArgument. Result { element, value }. next({ ...e, value }) rewrites the typing.on('ui.input', ...).
ui.select
Documented: An official docs page names this item.
Fires when the person picks from a Select that a render hook drew. e is { plugin, element, component, surface, value }.Input UiSelectArgument. Result { element, value }. next({ ...e, value }) rewrites the pick.on('ui.select', ...).
ui.message
Documented: An official docs page names this item.
Fires when a Client that this plugin drew posts from its surface module (surface.post(data)). Only this plugin's hooks see it.Input UiMessageArgument. Result { props? }. next({ ...e, data }) rewrites the data. One call for each instance in each frame.on('ui.message', ...).
ui.fault
Documented: An official docs page names this item.
Fires when a Client that this plugin drew failed on a surface. Its module did not load, its drawing failed, or its code failed after it drew.Input UiFaultInput. Result {}. Only this plugin's hooks see it. e.phase says when and e.reason says why.on('ui.fault', ...).
ui.scroll
Documented: An official docs page names this item.
Fires before the window of a site moves: the person's wheel or scroll keys on a Pane body or the AbovePrompt band (at its edges too), or $.ui.scroll.Input UiScrollInput. Result {} or { deny }. next({ ...e, offset }) scrolls elsewhere.on('ui.scroll', ...). Also $.ui.scroll(...).
ui.focus
Documented: An official docs page names this item.
Fires before the focus ring of a site moves: the person's Tab, arrows, or click in a Pane or the band, an autoFocus element taking it, or $.ui.focus.Input UiFocusInput. Result {} or { deny }. next({ ...e, element }) moves the focus to another element.on('ui.focus', ...). Also $.ui.focus(...).

Events Raised by UI Calls​

For each call, a hook above the caller returns next(e), { deny: reason }, or { value }.

ItemStatusThe argumentInput and value
ui.toast
Documented: An official docs page names this item.
$.ui.toast(text, { timeoutMs })Input { text: string, timeoutMs?: number }. Value void.
ui.status
Documented: An official docs page names this item.
$.ui.status(text). text undefined clears the line.Input { text: string | undefined }. Value void.
ui.log
Documented: An official docs page names this item.
$.ui.log(text, { to }). to is always present. next({ ...e, to: "debug" }) keeps a line off screen.Input { text: string, to: UiLogSink }. Value void.
ui.notice
Documented: An official docs page names this item.
$.ui.notice(tool_use_id, text)Input { tool_use_id: string, text: string | undefined }. Value void.
ui.invalidate
Documented: An official docs page names this item.
$.ui.invalidate(event)Input { event: InvalidatableEventName }. Value void.
ui.open
Documented: An official docs page names this item.
$.ui.open({ id, title, focus }). A hook above may retitle it or refuse with { deny }, never rename it.Input PaneOpenArgs. Value UiOpenResult.
ui.close
Documented: An official docs page names this item.
$.ui.close({ id }) with origin plugin. The engine raises it too, for the person (person) and for an unload (unload).Input PaneCloseInput. Value void.
ui.panes
Documented: An official docs page names this item.
$.ui.panes()Input NoArgs. Value readonly UiPane[].
ui.selection
Documented: An official docs page names this item.
$.ui.selection()Input NoArgs. Value UiSelection | undefined.
ui.copy
Documented: An official docs page names this item.
$.ui.copy({ text, surface }). surface takes the session's first surface when left out.Input UiCopyArgs. Value UiCopyResult.
ui.view
Documented: An official docs page names this item.
$.ui.view({ agentId }): whose transcript the main view shows. None means the main conversation.Input SiteView. Value UiViewResult.
ui.notify
Documented: An official docs page names this item.
$.ui.notify(text, { title }). title is the plugin's name when left out. Two mods that notify again on hearing a notification can echo each other without end.Input { text: string, title?: string }. Value UiNotifyResult.
ui.blit
Documented: An official docs page names this item.
$.ui.blit(...): the cells of a Raster or the source of a keyed Image. A hook above may rewrite either, or { deny }.Input UiBlitArgs. Value UiBlitResult.