Skip to content

System UI

@symbiote-native/system-ui wraps expo-system-ui — setting and reading the root view’s background color — so every SymbioteNative adapter can reach it, not just React. Like device and local auth, both exports here are one-shot async calls with no per-instance state, so there is no hook/composable/service to wrap — the React, Vue, Angular, and Svelte entry points are plain re-exports of the same core.

OS platform Support
iOS ✅ live
Android ✅ live
Framework adapter Support
React ✅ live
Vue ✅ live
Angular ✅ live
Svelte ✅ live
Terminal window
npm install @symbiote-native/system-ui

expo-system-ui and expo-modules-core come along as regular dependencies, pinned to exact versions — never install either yourself, and never add the expo meta-package to your project (it bundles its own Metro/Babel pipeline, which conflicts with this project’s own).

expo-system-ui needs no runtime permission on either platform — it only sets/reads a stored background color, nothing gated by a permission prompt.

All four adapters — React, Vue, Angular, Svelte — re-export the exact same two functions; there is no per-adapter hook/composable/service to reach for, since nothing here holds live state or a subscription.

import { useEffect } from 'react';
import { Text, View } from '@symbiote-native/react';
import { setBackgroundColorAsync } from '@symbiote-native/system-ui/react';
export default function RootScreen() {
useEffect(() => {
void setBackgroundColorAsync('black');
}, []);
return (
<View>
<Text>Root background set to black</Text>
</View>
);
}
Signature Description
setBackgroundColorAsync(color: ColorValue | null): Promise<void> Changes the root view background color. Call this outside of your component tree (e.g. in the root file), since it affects the whole app. null clears the override rather than setting an actual color
getBackgroundColorAsync(): Promise<ColorValue | null> Gets the current root view background color, in hex format. null if the background color is not set
  • setBackgroundColorAsync(null) clears the override rather than setting an actual color — it’s passed straight through to the native module without running processColor.
  • On web, the raw ColorValue is passed through untouched instead of being run through RN’s processColor — matching upstream, since processColor is a native-color-parsing step that doesn’t apply on that platform.
  • On iOS/Android, a non-null color is run through RN’s own processColor before reaching the native module — the same conversion RN’s style pipeline uses internally.

@symbiote-native/system-ui ships zero React/Vue/Angular logic in expo-system-ui itself — its two functions are hand-ported, verbatim, into this package’s own core/, resolving the native module through expo-modules-core’s requireNativeModule rather than the expo meta-package this project never installs:

packages/system-ui/src/
├── core/ # framework-agnostic: setBackgroundColorAsync/getBackgroundColorAsync;
│ # native-module.ts resolves the native module via expo-modules-core's
│ # requireNativeModule
├── react/ # @symbiote-native/system-ui/react — export * from '../core'
├── vue/ # @symbiote-native/system-ui/vue — export * from '../core'
├── angular/ # @symbiote-native/system-ui/angular — export * from '../core'
└── svelte/ # @symbiote-native/system-ui/svelte — export * from '../core'

Same shape as device’s and local auth’s adapter entries: single-file re-exports with no lifecycle code at all, since every export here is a stateless one-shot async call — there is nothing for a hook, composable, or service to subscribe to or clean up. The native code itself is never vendored or copied — expo-modules-autolinking resolves it straight out of node_modules (see the native setup guide).