Angular guide
The Angular adapter drives the same native Fabric engine as React, Vue, Svelte,
and Solid through a custom Renderer2/RendererFactory2 — Angular’s own
framework-agnostic rendering seam. Bootstrap is DOM-less: no
platform-browser, no zone.js. Angular renderer operations become engine
mutations, then Fabric commits real native views.
The examples/angular canary — the same component surface and engine as
the React, Vue, Svelte, and Solid canaries, driven through Renderer2 instead.
Minimal component
Section titled “Minimal component”import { Component } from '@angular/core';import { SYMBIOTE_ELEMENTS } from '@symbiote-native/angular';import './app.css';
@Component({ selector: 'app-root', standalone: true, imports: [SYMBIOTE_ELEMENTS], template: ` <view class="root"> <pressable (press)="increment()"> <text class="label">Count is {{ count }}</text> </pressable> </view> `,})export class App { count = 0;
increment(): void { this.count += 1; }}.root { flex: 1; align-items: center; justify-content: center;}.label { font-size: 24px;}StyleSheet.create works identically if you’d rather keep style objects
inline instead of a CSS file — see the Styling guide
for both paths.
Angular contract
Section titled “Angular contract”Angular is a standalone-components-only adapter:
- the 19 primitive tags (
view,pressable,text,text-input,switch, …) are Angular element directives, not components —SYMBIOTE_ELEMENTS(or an individual<Name>Element, e.g.ViewElement,PressableElement) declared in the component’simportsarray is what letsngtscaccept the lowercase tag with typed props; templates write the tag directly (<view>/<pressable>/<text>), matching every other adapter one-for-one; - every non-primitive SymbioteNative component (
FlatList,SectionList,VirtualizedList,VirtualizedSectionList,KeyboardAvoidingView, …) isstandalone: trueand imported directly the same way — there is noNgModule; - every component event is a real Angular
@Output()EventEmitter—(press)="onTap($event)",(longPress)="...",(hoverIn)="...",(valueChange)="...",(accessibilityAction)="...", and so on acrossPressable,Button,Touchable*,Switch,TextInput,Modal, and every other component. An event nobody templates costs nothing: an unbound(longPress)still skips arming the long-press timer, the same as an absent callback prop used to.TextInputis the one component with two outputs for what React/Vue fold into one callback:(valueChange)stays text-only (anEventEmittercarries one value, and text-only keeps[(value)]two-way binding working) while(change)is a second, separate output for the raw native event; - the one permanent exception is the scroll family —
onScroll,onScrollBeginDrag,onScrollEndDrag,onMomentumScrollBegin,onMomentumScrollEndstay callback inputs ([onScroll]="handler") onScrollViewand the list components, because they can carry anAnimated.event(...)marker for native-driven scroll and@Output()can’t bind an arbitrary value, only a template listener expression; - imperative handles use
@ViewChild(..., { read: ElementRef })— thenativeElementis the SymbioteNative host node, not a DOM element; - change detection is zoneless: the adapter runs on Angular’s own
ApplicationRef.tick(), wired in via the internalɵprovideZonelessChangeDetectionInternal()helper rather than the publicprovideZonelessChangeDetection()(which assumes aplatform-browserbootstrap this DOM-less renderer doesn’t use), so template updates batch the same way Vue’srequestCommit()does, without zone.js patching Hermes globals.
Read the exact API surface in the Angular API reference.