Reference
What RyUI has, against SwiftUI and Expo
What RyUI has, and what it doesn't yet.
Each row is something apps often need: how SwiftUI and Expo do it, and what RyUI has for it.
✓ has it · ◐ in part (what's missing is said) · ✗ not yet
Layout
| SwiftUI | Expo (React Native) | RyUI | |
|---|---|---|---|
| Stacks, spacing, padding, alignment | HStack, VStack, Spacer |
flexbox | ✓ Row, Column, Style (flexbox: Grow, Gap, Align, Justify, Wrap) |
| Overlays, absolute placement | ZStack, .overlay |
position: absolute |
✓ Style.Absolute, Top/Left/... |
| Scrolling | ScrollView |
ScrollView |
✓ Scroll (vertical, horizontal; out-of-sight rows leave the tree) |
| Lazy lists, cell recycling | List, LazyVStack |
FlatList |
✓ List (the platform's: UICollectionView, RecyclerView) |
| Grids | LazyVGrid |
FlatList numColumns |
✓ ListProps.Columns, Gap |
| Safe area, keyboard | automatic | SafeAreaView, KeyboardAvoidingView |
✓ SafeArea, UseEnvironment().Keyboard |
| Reading a view's size | GeometryReader |
onLayout |
✓ ViewProps.OnLayout |
| Aspect ratio, min/max sizes | .aspectRatio, .frame(min:max:) |
style | ✓ Style |
Controls
| SwiftUI | Expo | RyUI | |
|---|---|---|---|
| Text, styled text, links | Text, AttributedString |
Text |
✓ Text, RichText (spans, links, inline views, selection), ryui/markdown |
| Buttons (variants, icons, menus) | Button, Menu |
Pressable |
✓ Button (filled, tinted, gray, bordered; icon; menu), Menu, context menus |
| Text fields | TextField, SecureField, TextEditor |
TextInput |
✓ TextField (secure, keyboards, return keys, multiline) |
| Toggle, slider | Toggle, Slider |
community | ✓ Toggle, Slider |
| Segmented control | Picker(.segmented) |
community | ✓ Segmented |
| Date and time | DatePicker |
community | ✓ DatePicker (date, time, both) |
| Progress, spinner | ProgressView |
ActivityIndicator |
✓ Progress, Activity |
| Wheel and menu pickers, stepper | Picker, Stepper |
community | ✓ Wheel, Stepper, a menu from Button.Menu |
| Color picker | ColorPicker |
community | ✓ ColorPicker (iOS's system picker; on Android, which has none, a Material dialog of Google's palette, with opacity) |
| Icons | SF Symbols | @expo/vector-icons |
✓ Symbol (SF Symbols; Material Symbols on Android, a curated set) |
| Images (remote, cached, placeholders) | AsyncImage |
expo-image |
✓ Image (memory and disk cache, Placeholder) |
| Video | VideoPlayer |
expo-video |
✓ Video |
| Web content | WKWebView |
react-native-webview |
✓ WebView (URL, HTML, messages both ways, scripts before the page's, blocked requests, its state and history, downloads, new windows, cookies, a script's value; each request on Android); ryui/js runs JavaScript off screen |
| Maps | Map |
react-native-maps |
✗ (a native view through ui.Native meanwhile) |
| Custom drawing | Shape, Path, Canvas |
react-native-svg, Skia |
◐ Shape and Path (lines, curves, arcs, rects, ellipses; fill, stroke, caps, joins; an animatable trim); SVG icons drawn natively (ryui/svg); no immediate-mode canvas, no gradient fills |
| Native escape hatch | UIViewRepresentable |
native modules | ✓ ui.Native views, ui.Call modules |
Navigation and presentation
| SwiftUI | Expo (expo-router) | RyUI | |
|---|---|---|---|
| Stacks with native push, pop, back gestures | NavigationStack |
Stack | ✓ Stack, UseNavigator |
| Tabs | TabView |
Tabs | ✓ Tabs |
| Bar buttons, titles, search | .toolbar, .searchable |
header options | ✓ ScreenOptions (Actions, Search) |
| Sheets with detents | .sheet, .presentationDetents |
modal | ✓ Sheet (Detents, Grabber) |
| Alerts, action sheets | .alert, .confirmationDialog |
Alert |
✓ Alert (both styles) |
| Deep links, universal and app links | .onOpenURL |
Linking | ✓ OnOpenURL, ryui.json scheme and links |
| Pull to refresh, swipe actions | .refreshable, .swipeActions |
RefreshControl |
✓ |
Motion
| SwiftUI | Expo (Reanimated) | RyUI | |
|---|---|---|---|
| Animating changes | withAnimation |
withTiming, withSpring |
✓ Animate, AnimateWith (ease, linear, spring; repeat, autoreverse) |
| Transforms | .rotationEffect, .scaleEffect, .offset |
transform |
✓ Style.Transform |
| Enter and exit transitions | .transition |
entering/exiting | ✓ Style.Transition (Fade, Pop, SlideUp, your own) |
| Frame-driven animation | TimelineView(.animation) |
useFrameCallback |
✓ OnFrame |
| Shadows, gradients, blur | .shadow, LinearGradient, materials |
style, expo-linear-gradient, expo-blur | ✓ Shadow, LinearGradient, Material |
| Gestures | tap, long press, drag, magnify, rotate | Gesture Handler | ✓ tap, long press, pan, pinch, rotate, swipe |
| Shared-element transitions | matchedGeometryEffect, .navigationTransition(.zoom) |
shared transitions | ✓ Style.Match (a view grows from another's place and size), ScreenOptions.ZoomFrom (a pushed screen zooms out of a view: iOS 18's zoom; Material's container transform) |
| Haptics | sensoryFeedback |
expo-haptics |
✓ Haptic |
| Reduce Motion | accessibilityReduceMotion |
useReducedMotion |
✓ Environment.ReduceMotion (iOS transitions dissolve) |
Data and services
| SwiftUI / Apple | Expo | RyUI | |
|---|---|---|---|
| State | @State, @Observable |
hooks | ✓ signals (fine-grained: a write updates only what reads it) |
| Small persisted values | @AppStorage |
AsyncStorage | ✓ ryui/store |
| SQLite | SwiftData / GRDB | expo-sqlite |
✓ ryui/sqlite (migrations, typed queries, transactions, writes off the main thread, live queries that run again when a table they read is written, also with arguments that change: WatchWith) |
| Secure storage | Keychain | expo-secure-store |
✓ ryui/secure |
| Files, network | Foundation | expo-file-system, fetch |
✓ Go's os, net/http |
| Photos | PhotosPicker |
expo-image-picker |
✓ device.PickPhotos |
| Camera | AVFoundation | expo-camera |
✓ ryui/camera: Take (the system's camera), View (a live preview, front or back), Capture; ryui/camera/record records video with sound |
| Barcodes, QR codes | AVFoundation, Vision | expo-camera scanning |
✓ ryui/scan: live in camera.View (Scan: scan.Codes(...)) and in image files (scan.File); ML Kit on Android, only in the apps that import it |
| Location | Core Location | expo-location |
✓ ryui/location |
| Local notifications | UserNotifications | expo-notifications |
✓ ryui/notify (local; no push yet) |
| Push notifications | APNs | expo-notifications |
✗ |
| Clipboard, share sheet, browser | UIPasteboard, ShareLink, SFSafariViewController |
expo-clipboard, expo-sharing, expo-web-browser |
✓ Copy, device.Clipboard, Share, device.Browse |
| Keep awake, device info | isIdleTimerDisabled, UIDevice |
expo-keep-awake, expo-device |
✓ device.KeepAwake, device.GetInfo |
| Network state | NWPathMonitor |
expo-network |
✓ ryui/network (online, Wi-Fi or cellular, metered, Data Saver / Low Data Mode) |
| Saving to the gallery, Downloads | PHPhotoLibrary |
expo-media-library |
✓ ryui/library (MediaStore's collections; Photos, or Documents in Files) |
| Work in the background | beginBackgroundTask, BGTaskScheduler |
expo-task-manager |
◐ ryui/background: Android keeps the app running, its progress and buttons in a notification; iOS gives about 30 seconds; no scheduled tasks |
| Receiving shares from other apps | Share extension | share intent (community) | ✓ ui.OnShare (text and links, ryui.json's shareTarget; on iOS a share extension that opens the app) |
| Audio | AVAudioPlayer | expo-audio |
✓ ryui/audio (load, play, pause, seek, volume, loop); no recording |
| Custom fonts | .font(.custom) |
expo-font |
✓ Font.Family |
| Lifecycle | scenePhase |
AppState | ✓ app.OnLifecycle |
Appearance and accessibility
| SwiftUI | Expo | RyUI | |
|---|---|---|---|
| Dark mode, semantic colors, accent | automatic | useColorScheme |
✓ semantic colors, ryui.json accent (Material 3 dynamic color) |
| Dynamic Type, font scale | automatic | allowFontScaling |
✓ text styles and custom fonts scale |
| Screen reader labels, roles, hiding | .accessibilityLabel... |
accessibilityLabel... |
✓ Label, Hint, Role, Decorative; pressable views are buttons |
| Announcements | AccessibilityNotification.Announcement |
announceForAccessibility |
✓ Announce |
| Custom actions, adjustable | .accessibilityAction, .accessibilityAdjustableAction |
accessibilityActions |
✓ ViewProps.Actions, OnAdjust (and List swipe actions are TalkBack actions) |
Tooling
| Xcode / Expo | RyUI | |
|---|---|---|
| Live reload, keeping state | previews, Fast Refresh | ✓ ryui dev: the Go code runs on the Mac, reloads on save, keeps signals' values |
| Release builds and signing | Xcode, EAS Build | ✓ ryui build -ios (.ipa), ryui build -android (.aab, .apk) |
| GUI tests | XCUITest, Detox, Maestro | ✓ e2e/ (both platforms; a CI job for each, not yet run on GitHub) |
| Benchmarks | Instruments | ✓ bench/ (against SwiftUI and Compose) |
| Over-the-air updates | — | EAS Update: ✗ |
Not yet
In order of what apps miss most: push notifications and maps (both set
aside for now: push needs an APNs key and a Firebase project, Android's
maps a provider's choice). Maps can be an app's own native view through
ui.Native until then.