Svelte guide
The Svelte adapter drives the same native Fabric engine as React, Vue, and
Angular — but through a different seam than any of them. Svelte has no
official custom-renderer API yet (createRenderer from svelte/renderer is
still an unmerged proposal upstream), so instead of a framework-provided
rendering hook, this adapter patches a handful of globalThis DOM classes:
stock, unmodified compiled Svelte output believes it’s talking to the real
DOM, while every call it makes actually routes into
@symbiote-native/engine’s mutation API. Components are ordinary .svelte
files — nothing about authoring one is adapter-specific beyond the prop/event
shape below.
The examples/svelte canary — the same component surface and engine as the
React, Vue, and Angular canaries, driven through the DOM shim instead.
Minimal component
Section titled “Minimal component”<script lang="ts"> import { Pressable, Text, View } from '@symbiote-native/svelte';
let count = $state(0);</script>
<View class="root"> <Pressable onPress={() => (count += 1)}> <Text class="label">Count is {count}</Text> </Pressable></View>
<style> .root { flex: 1; align-items: center; justify-content: center; } .label { font-size: 24px; }</style>A component’s own <style> block is scoped by default, the same as real
Svelte — no CSS-file import needed here, though one still works identically.
StyleSheet.create works too if you’d rather keep style objects inline — see
the Styling guide for both paths.
Svelte contract
Section titled “Svelte contract”- every component event is a real camelCase prop —
onPress={onTap},onLongPress={...},onValueChange={...},onLayout={...}— not aon:xdirective and not kebab-cased like Vue’s templates; - children arrive as a
childrenprop typedSnippet, rendered internally via{@render children?.()}— Svelte 4’s<slot />has no place here. A component that hands state back to its children (Pressable’spressed) is consumed with a named{#snippet children(state)}block, Svelte’s own twin of a scoped slot; TextInput,Switch, and the Slider wrapper acceptbind:valueon top of their existingvalue/onValueChangecontract —value = $bindable()is the declaration a wrapper author reaches for to add the same sugar to their own controlled component;- Symbiote components forward no
bind:thisof their own —{@attach fn}is the way to reach a host node from app code, since it’s the one directive-shaped construct the Svelte compiler accepts on a component at all (use:/class:/style:are rejected there); <svelte:boundary>is a real, Svelte-exclusive error-boundary primitive among the four adapters today — wrap a subtree, provide afailedsnippet, and a thrown child tears down cleanly instead of leaving the app in a broken state;- Metro needs
@symbiote-native/svelte/metro-svelte-transformerwired as the Babel transformer for.sveltefiles, plusresolver.unstable_conditionNames: ['browser']— without it Metro resolves Svelte’s server-side build andmount()throwslifecycle_function_unavailableon the very first call.
Read the exact API surface in the Svelte API reference.