Callbacks
A callback is a member that carries an invocation from one place to another.
It is declared with the callback keyword, invoked by calling it like a function,
and reacted to by a handler set with the => arrow:
export component Example { callback hello; area := TouchArea { clicked => { root.hello(); } }}A callback may be declared in a component, on any element within a component, or in a global.
Declaration
Section titled “Declaration”A callback declaration names the callback and, optionally, its parameter types and return type:
export component Example { callback plain; // no parameters, no return value callback with-args(int, string); // two parameters callback with-return(int, int) -> int;}The following forms are allowed:
- No parentheses declares a callback with no parameters, as in
callback plain;. - Parentheses list the parameter types, as in
callback with-args(int, string);. A trailing comma after the last parameter is allowed. - A parameter may carry a name, written
name: type, as incallback c(foo: int, bar: string). Names are optional and may be mixed with unnamed parameters. The name carries no semantic value; a handler names its parameters independently. - A return type is written after
->and requires the parentheses to be present, even when there are no parameters:callback c() -> int. Writing-> typewithout parentheses is a compile error.
pure may precede callback to mark the callback as having no side effects (see Purity).
A pure callback may be called from a pure context, and its handler must itself be pure.
Calling an impure callback from a pure context is a compile error.
A callback name must not collide with another member of the same element. Declaring a callback whose name matches an existing property, function, or non-shadowable built-in callback is a compile error, and a duplicate callback declaration is a compile error.
Calling
Section titled “Calling”A callback is invoked with call syntax, passing arguments that match the declared parameter types:
export component Example { pure callback hello(int, int) -> int; property <int> result: hello(1, 2);}The number of arguments must match the declaration. If the callback has no handler, calling it does nothing and returns the default value of the return type.
Handlers
Section titled “Handlers”A handler reacts to the callback’s invocation.
It is written with => followed either by a code block or by a single expression:
export component Example { callback sum(int, int) -> int; sum(a, b) => { a + b }}- The handler names its parameters in parentheses. These names are local to the handler body and are independent of any names in the declaration. Parentheses may be omitted when the callback has no parameters.
- The body’s last expression is the return value; its type must match the callback’s return type.
- A callback has at most one handler. Setting a second handler for the same callback is a compile error.
A handler may be set on a callback declared in the same component or on a callback of a child element,
including a built-in callback such as TouchArea’s clicked.
The init callback
Section titled “The init callback”init is a built-in callback present on every element.
Its handler runs once when the element is instantiated.
init handlers run from the outermost component inward, so a component’s own init runs after
the init of the elements it contains.
Calling init explicitly does nothing and is deprecated.
A global can neither declare nor handle an init callback; both are compile errors.
Aliases
Section titled “Aliases”A callback alias forwards one callback to another, using the same <=> syntax as a two-way binding:
export component Example { callback clicked <=> area.clicked; area := TouchArea {}}- The alias must omit the parameter list; writing parentheses in an aliased declaration is a compile error.
- Both callbacks must have the same signature.
- Invoking either callback invokes the other, and a handler set on either responds to both.
An alias may target a global’s callback, written Global.callback.
A global may alias another global’s callback; this is the supported way for one global to implement another’s callback.
A non-global element cannot set a handler on an alias that targets a global’s callback,
because the element may be instantiated many times while the global is a singleton; this is a compile error.
Change Callbacks
Section titled “Change Callbacks”changed <property> => { ... } declares a handler that runs when a property’s value changes:
export component Example inherits Window { in-out property <string> value; changed value => { debug(self.value); }}- The target must be a property that exists on the element; naming a callback, a function, or a nonexistent member is a compile error.
- A change callback cannot be set on a private property that belongs to another component; this is a compile error.
- A property has at most one change callback per element; a duplicate is a compile error.
- The handler body may have side effects; it is not required to be pure.
A change callback is not invoked immediately. It is queued and runs in a later iteration of the event loop. It runs only if the value actually differs from the value at the previous run: multiple changes within one cycle collapse to a single invocation, and a value that changes and reverts before the callback runs produces no invocation.
Changing a property from within a change callback in a way that feeds back into the same property is undefined:
export component Example { in-out property <int> foo; property <int> bar: foo + 1; changed bar => { foo += 1; }}Such a chain, where one change callback triggers another, does not run unbounded. The runtime runs the queued change handlers in a loop that stops after ten passes, so a self-perpetuating sequence terminates without invoking the remaining handlers.
A change callback forces the property to be evaluated eagerly rather than lazily, and its side effects make the surrounding bindings impure. A declarative binding tracks its dependencies automatically and evaluates on demand, so a relationship that a binding can express should be expressed as a binding rather than a change callback.
© 2026 SixtyFPS GmbH