Vue NativeVue Native
Guide
Components
Composables
Navigation
Architecture
  • iOS
  • Android
  • macOS
GitHub
Guide
Components
Composables
Navigation
Architecture
  • iOS
  • Android
  • macOS
GitHub
  • Getting Started

    • Introduction
    • Installation
    • Your First App
    • Project Structure
  • Core Concepts

    • Components
    • Styling
    • Theming
    • TypeScript
    • Navigation
    • Navigation Components
    • Native Modules
    • Native Code Blocks
    • Hot Reload
  • UI Patterns

    • Forms and v-model
    • Shared Element Transitions
    • Teleport
    • Custom Native Components (escape hatch)
  • Quality & Debugging

    • Testing
    • Debugging
    • Error Handling
  • Platform Hardening

    • Security
    • Accessibility
    • Performance
  • Integration Guides

    • State Management
    • Deep Linking & Universal Links
    • State Persistence
    • Push Notifications
    • Error Reporting & Monitoring
  • Tooling

    • Managed Workflow
    • VS Code Extension
    • Neovim Plugin
  • Building & Releasing

    • Building Native Apps
    • Deployment & App Store Submission
  • Reference

    • Upgrade Guide
    • Migrating from React Native
    • Known Limitations & Platform Differences
    • Troubleshooting

Migrating from React Native

Vue Native targets the same mental model as React Native — native views driven by a JavaScript framework, Flexbox layout, a StyleSheet-style API — but the components are Vue components and the platform APIs are Vue composables. This guide maps the concepts you already know onto their Vue Native equivalents.

The component and composable names below are the real exports from @thelacanians/vue-native-runtime (see packages/runtime/src/components/ and packages/runtime/src/composables/).

Core concepts at a glance

React NativeVue NativeNotes
JSX components (<View>)Vue components (<VView>)All built-ins are prefixed with V.
Hooks (useState, useEffect)Vue reactivity (ref, computed, watch, lifecycle hooks)From vue / @vue/runtime-core.
StyleSheet.createcreateStyleSheetValidates + freezes style objects.
Platform / Platform.selectusePlatform / selectPlatformBuild-time constant, dead-code eliminated.
AsyncStorageuseAsyncStoragePromise-based, per-key serialized writes.
React Navigation@thelacanians/vue-native-navigationName-based routes, createRouter, RouterView.

Component mapping

React NativeVue NativeDoc
ViewVViewVView
TextVTextVText
ImageVImageVImage
ScrollViewVScrollViewVScrollView
FlatListVFlatList (virtualized) or VList (native table/recycler)VFlatList, VList
SectionListVSectionListVSectionList
TextInputVInputVInput
Pressable / TouchableOpacityVPressable (or VButton for a styled button)VPressable, VButton
SwitchVSwitchVSwitch
ActivityIndicatorVActivityIndicatorVActivityIndicator
ModalVModalVModal
RefreshControlVRefreshControlVRefreshControl
SafeAreaViewVSafeAreaVSafeArea
KeyboardAvoidingViewVKeyboardAvoidingVKeyboardAvoiding
StatusBarVStatusBarVStatusBar
WebView (community)VWebViewVWebView
Video (community)VVideoVVideo

Vue Native also ships components with no direct RN-core equivalent, such as VSlider, VSegmentedControl, VCheckbox, VRadio, VDropdown, VPicker, VAlertDialog, VActionSheet, VProgressBar, VErrorBoundary, VTransition, and the macOS-only VToolbar, VSplitView, and VOutlineView.

Event prop naming

RN uses onPress, onChangeText, etc. Vue Native keeps the same camelCase names but they are wired as Vue props/events:

<!-- React Native: <TouchableOpacity onPress={handlePress}> -->
<VButton :onPress="handlePress">
  <VText>Tap me</VText>
</VButton>

<!-- React Native: <TextInput onChangeText={setText} /> -->
<VInput :onChangeText="setText" />

Composables ↔ hooks / modules

Platform capabilities are exposed as composables (functions you call in <script setup>), not hooks or imperative native modules.

React NativeVue NativeDoc
Platform.OS / flagsusePlatform()usePlatform
Platform.select({...})selectPlatform({...})usePlatform
AsyncStorageuseAsyncStorage()useAsyncStorage
Keychain / secure storageuseSecureStorage()useSecureStorage
Animated / ReanimateduseAnimation()useAnimation
useWindowDimensions / DimensionsuseDimensions()useDimensions
AppStateuseAppState()useAppState
NetInfouseNetwork()useNetwork
useColorSchemeuseColorScheme()useColorScheme
BackHandleruseBackHandler()useBackHandler
LinkinguseLinking()useLinking
ClipboarduseClipboard()useClipboard
ShareuseShare()useShare
KeyboarduseKeyboard()useKeyboard
fetch wrappers / axiosuseHttp()useHttp
WebSocketuseWebSocket()useWebSocket
react-native-haptic-feedbackuseHaptics()useHaptics
react-native-permissionsusePermissions()usePermissions
react-native-gesture-handleruseGesture()useGesture
expo-local-authenticationuseBiometry()useBiometry
expo-camerauseCamera()useCamera
react-native-iapuseIAP()useIAP
react-native-ota-hot-updateuseOTAUpdate()useOTAUpdate

Styling differences

The styling API is deliberately close to RN's StyleSheet, with a few important differences:

createStyleSheet instead of StyleSheet.create

import { createStyleSheet } from '@thelacanians/vue-native-runtime'

const styles = createStyleSheet({
  container: { flex: 1, padding: 16, backgroundColor: '#fff' },
  title: { fontSize: 20, fontWeight: '600', color: '#111' },
})

In development, unknown style properties trigger a console warning; the returned objects are frozen.

No percentages on padding/margin

padding and margin (and all padding* / margin* variants) accept numbers only. Percentage strings are not supported (a breaking change in v0.8.0). Percentage values are still supported on width, height, min*/max*, flexBasis, and top/right/bottom/left. Compute padding/margin from the parent dimension yourself if needed (e.g. with useDimensions).

hairlineWidth

import { hairlineWidth } from '@thelacanians/vue-native-runtime'

const styles = createStyleSheet({
  separator: { height: hairlineWidth, backgroundColor: '#ccc' },
})

hairlineWidth is 0.5, mirroring StyleSheet.hairlineWidth.

Shadows: iOS vs Android

iOS uses shadowColor / shadowOffset / shadowOpacity / shadowRadius; Android ignores those and requires elevation. Set both for cross-platform cards. See Styling for the full property reference.

Theming

RN has no built-in theme system; most apps roll their own or use a library. Vue Native ships one: createTheme + <ThemeProvider> + createDynamicStyleSheet. See the Theming guide.

Navigation

React Navigation resolves screens by route object; Vue Native's @thelacanians/vue-native-navigation resolves them by name.

import { createRouter } from '@thelacanians/vue-native-navigation'
import Home from './screens/Home.vue'
import Detail from './screens/Detail.vue'

// Routes are keyed by NAME — there is no `path` field.
const router = createRouter([
  { name: 'Home', component: Home },
  { name: 'Detail', component: Detail },
])

export default router
React NavigationVue Native navigation
createNativeStackNavigator + <Stack.Screen name>createRouter([{ name, component }])
navigation.navigate('Detail', { id })router.push('Detail', { id }) (or router.navigate)
navigation.goBack()router.pop() (or router.goBack())
navigation.replace(...)router.replace(...)
navigation.reset(...)router.reset(...)
useNavigation()useRouter()
useRoute() (route.params)useRoute() (route.value.params)
navigation.setOptions({ title })Per-route options: { title } in RouteConfig
Deep linking linking configcreateRouter({ routes, linking })
Bottom tabs / drawer navigatorsVTabBar / VDrawer components + nested routers

Guards return a route name to redirect, or false to cancel:

router.beforeEach((to, from) => {
  if (to.config.name !== 'Login' && !isAuthenticated()) {
    return 'Login' // redirect by name
  }
})

See the Navigation guide and the Navigation section for details.

A minimal side-by-side

// React Native
import { View, Text, StyleSheet } from 'react-native'

export default function Hello({ name }) {
  return (
    <View style={styles.box}>
      <Text style={styles.title}>Hello {name}</Text>
    </View>
  )
}

const styles = StyleSheet.create({
  box: { flex: 1, padding: 16, justifyContent: 'center' },
  title: { fontSize: 24, color: '#111' },
})
<!-- Vue Native -->
<script setup>
import { createStyleSheet } from '@thelacanians/vue-native-runtime'

defineProps({ name: String })

const styles = createStyleSheet({
  box: { flex: 1, padding: 16, justifyContent: 'center' },
  title: { fontSize: 24, color: '#111' },
})
</script>

<template>
  <VView :style="styles.box">
    <VText :style="styles.title">Hello {{ name }}</VText>
  </VView>
</template>

See also

  • Components — how Vue Native components work.
  • Styling — full style property reference.
  • Theming — built-in design tokens and dark mode.
  • Navigation — routing and screen lifecycle.
Edit this page
Last Updated: 7/28/26, 4:10 PM
Contributors: github-actions[bot]
Prev
Upgrade Guide
Next
Known Limitations & Platform Differences