Multi-Window Applications with React Native visionOS

Jul 17, 2024

Multi-Window Applications with React Native visionOS

Learn how to implement multi-window functionality in your React Native visionOS app for enhanced user experiences and flexible content presentation. Elevate your visionOS development with practical steps and insights.

Author

Shivraj Kumar
Shivraj KumarPrincipal Technical Consultant.

Subject Matter Expert

Tarunlal Rajak
Tarunlal RajakSoftware Engineer III

As we continue to explore React Native's capabilities for visionOS development, we encounter exciting opportunities to enhance user experiences. In this article, we'll explore creating and managing multiple windows in your visionOS application using the React Native visionOS-specific Window Manager API.

We will work with an existing YouTube-like application, expanding its functionality to support multiple windows. This approach allows us to focus on the multi-window implementation while building upon a familiar foundation.

Prerequisites

Before we begin, ensure you have:

  • A React Native visionOS development environment set up
  • Basic familiarity with React Native development
  • The latest version of necessary dependencies installed in your project
  • An existing visionOS application (like our YouTube clone) to build upon

To set up your environment or create a base application, refer to the React Native visionOS setup, as detailed in our introductory guide.

Implementing Multi-Window Functionality

Let's walk through the process of adding multi-window support to your visionOS application.

Step 1: Configure Info.plist

First, we need to enable multiple scene support in your Info.plist file:

<dict>
  <key>UIApplicationSceneManifest</key>
  <dict>
    <key>UIApplicationPreferredDefaultSceneSessionRole</key>
    <string>UIWindowSceneSessionRolApplication</string>
    <key>UIApplicationSupportsMultipleScenes</key>
    <true/>
    <key>UISceneConfigurations</key>
    <dict/>
  </dict>
</dict>

Step 2: Create the Second Window Component

Now, let's create a component for our second window. In this example, we'll display a video thumbnail:

// SecondWindow.tsx
import React from 'react';
import { Image, StyleSheet, View } from 'react-native';
import useVideoStore from '../store/store';

const SecondWindow = () => {
  const [allVideos, indexVideo] = useVideoStore(state => [
    state.allVideos,
    state.indexVideo,
  ]);

  return (
    <View style={styles.container}>
      <Image source={{uri: allVideos[indexVideo].thumb}} style={styles.image} />
    </View>
  );
};

const styles = StyleSheet.create({
  container: {
    flex: 1,
    backgroundColor: 'white',
  },
  image: {
    flex: 1,
    resizeMode: 'cover',
  },
});

export default SecondWindow;

Step 3: Register the Second Window Component

In your index.js file, register the SecondWindow component:

Step 4: Modify App.swift for Native Integration

Update your App.swift file to support the second window:

import SwiftUI
import React
import React_RCTSwiftExtensions

@main
struct YoutubeCloneApp: App {
  @UIApplicationDelegateAdaptor var delegate: AppDelegate
  @Environment(\\.reactContext) private var reactContext

  var body: some Scene {
    RCTMainWindow(moduleName: "YoutubeClone")
    RCTWindow(id: "SecondWindow", sceneData: reactContext.getSceneData(id: "SecondWindow"))
  }
}

Step 5: Implement Window Management in JavaScript

Use the Window Manager API to control the second window:

import React from 'react';
import { Button, View, StyleSheet } from 'react-native';
import { WindowManager } from '@callstack/react-native-visionos';
import useVideoStore from '../store/store';

const WindowControl = () => {
  const secondWindow = WindowManager.getWindow("SecondWindow");
  const increment = useVideoStore(state => state.increment);

  return (
    <View style={styles.container}>
      <Button
        title="Open Second Window"
        onPress={() => secondWindow.open()}
      />
      <Button
        title="Next Video"
        onPress={increment}
      />
    </View>
  );
};

const styles = StyleSheet.create({
  container: {
    flexDirection: 'row',
    justifyContent: 'space-around',
    padding: 10,
  },
});

export default WindowControl;

Managing State with Zustand

To manage state across windows, we'll use Zustand. Here's a basic store setup:

// store.ts
import create from 'zustand';

interface VideoType {
  thumb: string;
  // Add other video properties as needed
}

interface VideoStore {
  allVideos: VideoType[];
  indexVideo: number;
  setAllVideos: (videos: VideoType[]) => void;
  increment: () => void;
}

const useVideoStore = create<VideoStore>((set) => ({
  allVideos: [],
  indexVideo: 0,
  setAllVideos: (videos) => set({ allVideos: videos }),
  increment: () => set((state) => ({ indexVideo: (state.indexVideo + 1) % state.allVideos.length })),
}));

export default useVideoStore;

Putting It All Together

Now that we have all the pieces let's see how they work together:

visionos.mov

  1. The main window displays video content and the WindowControl component.
  2. When the user presses "Open Second Window," a new window shows the current video's thumbnail.
  3. Pressing "Next Video" updates the indexVideo in the store, which automatically updates the thumbnail in the second window.

Next step would be to move the video to the second window, which needs to be tried out.

Conclusion

Implementing multi-window functionality in your React Native visionOS app can create more immersive and interactive user experiences. This approach allows for flexible content presentation and enhanced user engagement.

As you continue to explore visionOS development with React Native, consider how multi-window support can elevate your application's user experience. Consider various user interactions and edge cases and thoroughly test your implementation.

We hope this guide helps you unlock new possibilities in your visionOS applications. Happy coding!

Subscribe to Our Newsletter

More from the engineering frontline.

Dive deep into our research and insights on design, development, and the impact of various trends to businesses.
Insight
AntFlow AI: An Agentic Development Framework That Turns Software Requirements into Reviewed Code
Sep 15, 2026

AntFlow AI: An Agentic Development Framework That Turns Software Requirements into Reviewed Code

A look at how AntFlow AI turns software requirements into reviewed code using AI agents, human approval gates, dependency-aware execution, and end-to-end traceability from brief to pull request.

Insight
Building Local LLMs Using Dart FFI And llama.cpp: Beyond Wrapper Packages
Sep 11, 2026

Building Local LLMs Using Dart FFI And llama.cpp: Beyond Wrapper Packages

Build local LLMs in Flutter with Dart FFI and llama.cpp, and see how native bridges, GGUF models, memory management, and token streaming enable private, on-device AI.

Insight
My Flutter App Froze With Three Photos on Screen. Here's What I Was Doing Wrong
Sep 11, 2026

My Flutter App Froze With Three Photos on Screen. Here's What I Was Doing Wrong

This blog explains how rethinking Flutter’s image-processing architecture fixed severe performance issues and improved rendering efficiency.

Insight
Building a Production-Ready Canva-like Editor with Konva.js, React 19 and Next.js 15
Sep 10, 2026

Building a Production-Ready Canva-like Editor with Konva.js, React 19 and Next.js 15

This blog explains how to build a production-ready canvas editor with Konva.js, React, and Next.js, covering architecture, performance, and key engineering decisions.

Insight
What a PHP-to-NestJS Banking Migration Taught Us About Architecture, Security, and Trust
Sep 8, 2026

What a PHP-to-NestJS Banking Migration Taught Us About Architecture, Security, and Trust

This blog explores the architecture, security, performance, and documentation lessons from migrating a legacy PHP/Laravel banking platform to NestJS.

Insight
Building Production-Grade Video Thumbnail Scrubbing in the Browser: HLS, Frame Extraction, Caching, and Performance Trade-offs
Sep 7, 2026

Building Production-Grade Video Thumbnail Scrubbing in the Browser: HLS, Frame Extraction, Caching, and Performance Trade-offs

This blog explains how to build responsive video thumbnail scrubbing in the browser for local files and HLS streams, covering frame extraction, caching, and performance trade-offs.

Insight
The Agent Can See Your App. How Often Can It Look?
Sep 4, 2026

The Agent Can See Your App. How Often Can It Look?

AI coding agents can now interact with mobile apps, but their effectiveness depends on iteration speed. This blog explores how React Native architecture influences feedback loops and AI-driven developer productivity.

The Right Conversation Can

Save You Six Months.

Book a call