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

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

    • Components
    • Styling
    • Navigation
    • Native Modules
    • Native Code Blocks
    • Hot Reload
  • Advanced

    • Error Handling
    • Accessibility
    • TypeScript
    • Performance
    • Shared Element Transitions
    • Testing
    • Security
    • Debugging
    • Teleport
    • Forms and v-model
  • 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 for Release
    • Deployment & App Store Submission
  • Reference

    • Migration & Upgrade Guide
    • Known Limitations & Platform Differences
    • Troubleshooting

Known Limitations & Platform Differences

Vue Native renders to native UIKit views (iOS) and Android Views (Android), not to a WebView. JavaScript runs inside JavaScriptCore (iOS) and J2V8/V8 (Android) -- environments that provide no browser APIs. This page documents what is available, what is not, and where the two platforms diverge.

No DOM

There is no document, no window, no navigator, and no HTML element tree. Any code that references browser globals will throw a ReferenceError at runtime.

Browser APIVue Native Replacement
document.getElementById()Use ref on a component and the bridge node system
window.addEventListener()useAppState, useKeyboard, useDimensions
localStorage / sessionStorageuseAsyncStorage (key-value) or useSecureStorage (encrypted)
window.locationuseRouter and useLinking
window.fetchPolyfilled -- works as expected (backed by URLSession / OkHttp)
alert() / confirm()VAlertDialog / VActionSheet components
navigator.clipboarduseClipboard
navigator.geolocationuseGeolocation
navigator.vibrateuseHaptics

Caution

Libraries that access document or window at import time will crash the app during bundle evaluation, before any component renders. Always verify third-party libraries in a native build, not just in a web browser.

CSS Limitations

Vue Native uses Yoga (iOS, via FlexLayout) and FlexboxLayout (Android) for layout. This is a subset of CSS Flexbox, not the full CSS specification.

Supported Layout Properties

All standard Flexbox properties are available: flex, flexDirection, flexWrap, alignItems, alignSelf, justifyContent, alignContent, flexGrow, flexShrink, flexBasis, gap, rowGap, columnGap.

Box model properties are supported: width, height, minWidth, maxWidth, minHeight, maxHeight, padding, margin, borderWidth. Percentage values work for dimensions and padding/margin.

See the Styling guide for the full property reference.

Not Supported

CSS FeatureStatusWorkaround
CSS GridNot availableUse nested Flexbox containers
floatNot availableUse flexDirection: 'row'
position: fixedNot availableUse position: 'absolute' inside a flex container
z-index stacking contextsNot availableControl rendering order by component tree order (later siblings render on top)
CSS transitions / @keyframesNot availableUse useAnimation (runs natively)
Media queriesNot availableUse useDimensions to read screen size reactively
Pseudo-classes (:hover, :focus)Not availableUse VPressable with press state callbacks
box-shadowiOS only (shadowColor, shadowOffset, shadowOpacity, shadowRadius)Use elevation on Android
transform (CSS syntax)Not availableUse useAnimation with translateX, translateY, scale, rotate
overflow: scrollNot availableUse VScrollView or VList
CSS variables / calc()Not availableCompute values in JavaScript
display: noneNot availableUse v-if to remove or v-show (sets opacity: 0 + disables interaction)

Tips

Think of styling in Vue Native as "Flexbox plus appearance properties." If a CSS feature requires the browser's layout engine or CSSOM, it will not work here.

JavaScript Environment

Bundles are compiled to IIFE format targeting ES2020. There is no ESM import() at runtime -- all code is bundled into a single file by Vite.

Polyfilled APIs (Available)

These APIs are injected by the native runtime before the bundle executes:

  • setTimeout / clearTimeout
  • setInterval / clearInterval
  • queueMicrotask
  • requestAnimationFrame / cancelAnimationFrame
  • console (log, warn, error, info, debug)
  • fetch / Request / Response / Headers
  • Promise (native in JSC/V8)
  • URL / URLSearchParams
  • TextEncoder / TextDecoder
  • atob / btoa
  • crypto.getRandomValues
  • performance.now()
  • globalThis

Not Available

APIReason
Web Workers / SharedWorkerSingle JS thread; no worker runtime
IndexedDBBrowser storage API; use useDatabase for SQLite
Service WorkersNo browser registration model
WebGL / Canvas APINo <canvas> element; use VImage for graphics
WebAssemblyNot exposed in JSC/J2V8 by default
MutationObserverNo DOM to observe
ResizeObserver / IntersectionObserverNo DOM; use useDimensions or VList visibility callbacks
XMLHttpRequestUse fetch or useHttp instead
Blob / FileUse useFileSystem for file operations
EventSource (SSE)Use useWebSocket for real-time connections

Warning

Top-level await is not supported in IIFE bundles. Wrap async initialization inside an async function and call it.

Third-Party Library Compatibility

Libraries That Work

Any pure JavaScript library with no DOM or Node.js dependencies works out of the box:

  • Utilities: lodash, ramda, date-fns, dayjs
  • Validation: zod, yup, valibot, joi
  • State: pinia (with Vue Native's Vue instance), zustand (vanilla store)
  • Data: uuid, nanoid, immer, superjson
  • Parsing: papaparse, yaml, toml
  • Math/crypto: bignumber.js, tweetnacl

Libraries That Do Not Work

Any library that imports or accesses browser APIs at the module level will fail:

  • React ecosystem: react, react-dom, and all React component libraries
  • DOM manipulation: jQuery, cheerio (server-only OK), D3 (rendering parts)
  • CSS-in-JS: styled-components, emotion, tailwind (runtime), stitches
  • Browser routing: vue-router (web version) -- use @thelacanians/vue-native-navigation
  • Canvas/WebGL: three.js, PixiJS, chart.js, p5.js

Libraries Needing Adaptation

LibraryIssueUse Instead
axiosUses XMLHttpRequest internallyuseHttp (built-in, native networking)
socket.io-clientDepends on browser WebSocket + pollinguseWebSocket (native implementation)
vue-routerDepends on browser History API@thelacanians/vue-native-navigation
async-storage (React Native)Different bridge protocoluseAsyncStorage (built-in)

Platform Differences (iOS vs Android)

While Vue Native abstracts most platform details, certain behaviors differ between iOS and Android.

Keyboard Handling

BehavioriOSAndroid
Default resize behaviorContent pushed up automaticallyRequires android:windowSoftInputMode="adjustResize" in manifest
VKeyboardAvoiding behavior prop"padding" (recommended)"padding" or "height"
Keyboard dismissTap outside inputBack button or tap outside

Status Bar

BehavioriOSAndroid
Light/dark textVStatusBar barStyle="light-content"Same API, but may require android:windowLightStatusBar
TranslucentTranslucent by defaultMust set translucent={true} explicitly
Background colorNot directly settable (use VView behind it)Settable via backgroundColor prop

Safe Areas & Notch

  • iOS: VSafeArea insets for notch, Dynamic Island, and home indicator.
  • Android: VSafeArea insets for status bar and navigation bar. Cutout (notch) handling depends on android:windowLayoutInDisplayCutoutMode.

Back Navigation

  • iOS: Swipe-from-left-edge gesture is handled automatically by the stack navigator.
  • Android: Hardware/gesture back button must be intercepted with useBackHandler. The stack navigator handles this by default, but custom back logic requires explicit handling.

Shadows

  • iOS: Uses shadowColor, shadowOffset, shadowOpacity, shadowRadius (Core Animation).
  • Android: Uses elevation (Material Design shadow). The four iOS shadow properties are ignored on Android.

Permissions

  • iOS: Permissions are requested via system dialogs. Denied permissions can only be changed in Settings. The Info.plist must include usage description strings.
  • Android: Permissions use the runtime permission model (API 23+). Denied permissions can be re-requested unless "Don't ask again" was selected. The AndroidManifest.xml must declare permissions.

Performance Boundaries

Vue Native is designed for typical mobile app workloads. Be aware of these practical limits:

ScenarioGuideline
VList itemsHandles up to ~500 items smoothly. Beyond 1,000 items, use pagination or incremental loading.
View tree depthKeep below 10-15 levels of nesting. Deeply nested trees increase layout calculation time.
Total native nodesApps with 10,000+ simultaneous nodes may see increased memory pressure. Unmount screens and use VList virtualization.
Heavy computationAll JS runs on a single thread. Computations over ~16ms block the frame. Break large work into chunks with setTimeout or requestAnimationFrame.
Bridge operationsVue Native batches bridge calls per microtask, but thousands of prop updates in a single tick will stall rendering. Use useAnimation for frame-by-frame visual changes.
ImagesHigh-resolution images consume significant memory. Size images appropriately and avoid loading dozens of full-resolution images simultaneously.

Tips

Use usePerformance to profile your app. Watch for FPS drops below 55, steadily growing memory, or bridge operation spikes. See the Performance guide for details.

Navigation Limitations

Vue Native navigation is a native stack managed in JavaScript -- not browser history.

  • There is no URL bar, no <a> tags, and no window.history.
  • Use useRouter().push(), pop(), replace(), and reset() for all navigation.
  • Deep linking is supported via useLinking and the router's linking config, but the URL is parsed and mapped to a route -- there is no browser navigation happening.
  • The browser-based vue-router package is not compatible. Use @thelacanians/vue-native-navigation.
  • Tab and drawer navigators maintain their own stacks. Nested navigators are supported but add complexity; keep nesting to two levels when possible.

Warning

Calling router.reset() destroys the entire navigation stack and rebuilds it. Use it only for flows like sign-out where you need to clear all screen state.

Edit this page
Last Updated: 2/28/26, 11:24 PM
Contributors: Abdul Hamid, Claude Opus 4.6
Prev
Migration & Upgrade Guide
Next
Troubleshooting