Skip to content

Events

Native Fabric events come back to the engine. Each adapter then exposes them in that framework’s idiom: React callback props, Vue typed emits (plus v-model on controlled components), Angular real @Output() EventEmitters, and Svelte plain callback props — the DOM-shim adapter passes the same event object straight through, with no framework-specific wrapper or emit translation — with one permanent exception, the scroll-family events, which stay callback inputs (see the caveat below).

<Switch value={enabled} onValueChange={setEnabled} />
<TextInput value={name} onValueChange={setName} />
<Pressable onPress={() => setCount(count + 1)} />

The payload is the same concept. The public API is framework-shaped.

Some events are native passthrough events. They travel through the engine as onX listeners and should not be declared as Vue emits unless the Vue component actually consumes and re-emits them.

Other events are adapter-level conveniences. Examples:

Concept React Vue Angular Svelte
Press onPress @press (press) onPress
Switch value onValueChange(value, event) @value-change
or v-model
(valueChange) (value only) onValueChange(value, event)
Text input text onValueChange(text, event) @value-change
or v-model
(valueChange) (text only) onValueChange(text, event)
Text input raw event (same callback, 2nd arg) (same emit, 2nd arg) (change) (separate output) (same callback, 2nd arg)

React, Vue, and Svelte merged TextInput’s old onChangeText/onChange pair into one onValueChange(text, event) callback — there’s only ever one underlying native event. Angular keeps two separate @Output()s instead, because an EventEmitter carries exactly one value: valueChange stays text-only (so [(value)] two-way binding keeps working) and change is a second output for the raw event. Switch follows the same shape one level simpler: React’s onValueChange, Vue’s @value-change, and Svelte’s onValueChange all receive the native event as a second argument, but Angular’s valueChange stays single-value (just the boolean) since there’s no second output to split it into.

This split matters because Vue removes declared emit listeners from attrs. If a native passthrough listener is declared as an emit by mistake, the engine may never see it.

Switch and TextInput follow React Native’s controlled-component rules. If the native view reports a new value but the parent does not update the value prop, SymbioteNative commands native back to the JavaScript value.

That correction logic is shared in @symbiote-native/components; React, Vue, Angular, and Svelte each only wire it to their own lifecycle systems.