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), and Angular real @Output() EventEmitters — with one permanent exception, the scroll-family events, which stay callback inputs (see the caveat below).

React:

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

Vue — typed emits, or v-model on the controlled components that support it:

<Switch v-model="enabled" />
<TextInput v-model="name" />
<Pressable @press="count++" />

Angular — real @Output() EventEmitters everywhere, including Switch and TextInput:

template: `
<Switch [value]="enabled" (valueChange)="setEnabled($event)" />
<TextInput [value]="name" (valueChange)="setName($event)" />
<Pressable (press)="count = 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
Press onPress @press (press)
Switch value onValueChange(value, event) @value-change
or v-model
(valueChange) (value only)
Text input text onValueChange(text, event) @value-change
or v-model
(valueChange) (text only)
Text input raw event (same callback, 2nd arg) (same emit, 2nd arg) (change) (separate output)

React and Vue 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 and Vue’s @value-change both 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, and Angular each only wire it to their own lifecycle systems.