---
modificationDate: February 26, 2026
title: RNHostView
description: A component that enables React Native views inside SwiftUI.
sourceCodeUrl: 'https://github.com/expo/expo/tree/main/packages/expo-ui'
packageName: '@expo/ui'
platforms: ['ios', 'tvos']
---

<AgentInstructions>

## Submitting Feedback

If this page contains errors, outdated information, or gaps that blocked you from completing a task, report it so the docs can be improved:

curl -X POST https://api.expo.dev/v2/feedback/docs-send -H 'Content-Type: application/json' -d '{"url":"/versions/v55.0.0/sdk/ui/swift-ui/rnhostview/","feedback":"🤖 Agent feedback: <specific, actionable description>"}'

Only submit when you have something specific and actionable to report.

</AgentInstructions>

# RNHostView

A component that enables React Native views inside SwiftUI.
iOS, tvOS

> For the complete documentation index, see [llms.txt](/llms.txt). Use this file to discover all available pages.

A component that enables proper layout behavior when React Native views are rendered inside SwiftUI components. It syncs layout information from SwiftUI back to React Native's Yoga layout system by updating the shadow node size.

When React Native views are placed inside SwiftUI components like [`BottomSheet`](/versions/v55.0.0/sdk/ui/swift-ui/bottomsheet), [`Popover`](/versions/v55.0.0/sdk/ui/swift-ui/popover) or [`HStack`](/versions/v55.0.0/sdk/ui/swift-ui/hstack) and so on, the layout systems need to communicate. `RNHostView` bridges this gap:

-   **With `matchContents`**: The shadow node size is set to match the child React Native view's intrinsic size, allowing the SwiftUI parent to size itself based on the React Native content.
-   **Without `matchContents`**: The shadow node size is set to match the parent SwiftUI view's size, allowing the React Native content to fill the available space (useful for `flex: 1` layouts).

## Installation

```sh
npx expo install @expo/ui
```

If you are installing this in an [existing React Native app](/bare/overview), make sure to [install `expo`](/bare/installing-expo-modules) in your project.

## Usage

### Basic usage with matchContents

Use `matchContents` when you want the SwiftUI parent to size itself based on the React Native content.

```tsx
import { useState } from 'react';
import { Pressable, Text, View } from 'react-native';
import { Host, BottomSheet, Button, RNHostView } from '@expo/ui/swift-ui';

function Example() {
  const [isPresented, setIsPresented] = useState(false);

  return (
    <Host style={{ flex: 1 }}>
      <Button label="Open Sheet" onPress={() => setIsPresented(true)} />
      <BottomSheet isOpened={isPresented} onIsOpenedChange={setIsPresented}>
        <RNHostView matchContents>
          <View style={{ padding: 24 }}>
            <Text style={{ fontSize: 18, fontWeight: 'bold' }}>React Native Content</Text>
            <Pressable
              style={{ backgroundColor: '#007AFF', padding: 12, borderRadius: 8, marginTop: 16 }}
              onPress={() => setIsPresented(false)}>
              <Text style={{ color: 'white', textAlign: 'center' }}>Close</Text>
            </Pressable>
          </View>
        </RNHostView>
      </BottomSheet>
    </Host>
  );
}
```

### Flexible content without matchContents

When using `flex: 1` in your React Native content, omit the `matchContents` prop so the content fills the available SwiftUI space.

```tsx
import { useState } from 'react';
import { Text, View } from 'react-native';
import { Host, BottomSheet, Button, RNHostView } from '@expo/ui/swift-ui';

function Example() {
  const [isPresented, setIsPresented] = useState(false);

  return (
    <Host style={{ flex: 1 }}>
      <Button label="Open Sheet" onPress={() => setIsPresented(true)} />
      <BottomSheet
        isOpened={isPresented}
        onIsOpenedChange={setIsPresented}
        presentationDetents={['medium', 'large']}>
        <RNHostView>
          <View style={{ flex: 1, backgroundColor: '#007AFF', padding: 24 }}>
            <Text style={{ color: 'white', fontSize: 18 }}>
              This content fills the available space
            </Text>
          </View>
        </RNHostView>
      </BottomSheet>
    </Host>
  );
}
```

### Usage with Popover

`RNHostView` works well inside [`Popover`](/versions/latest/sdk/ui/swift-ui/popover) to display interactive React Native content.

```tsx
import { useState } from 'react';
import { Pressable, Text, View } from 'react-native';
import { Host, Button, Popover, RNHostView } from '@expo/ui/swift-ui';

function Example() {
  const [isPresented, setIsPresented] = useState(false);
  const [counter, setCounter] = useState(0);

  return (
    <Host style={{ flex: 1 }}>
      <Popover isPresented={isPresented} onIsPresentedChange={setIsPresented}>
        <Popover.Trigger>
          <Button onPress={() => setIsPresented(true)} label="Show Popover" />
        </Popover.Trigger>
        <Popover.Content>
          <RNHostView matchContents>
            <View style={{ padding: 24 }}>
              <Text style={{ fontSize: 16, fontWeight: 'bold', marginBottom: 8 }}>
                React Native Content
              </Text>
              <Text style={{ color: '#666', marginBottom: 12 }}>Counter: {counter}</Text>
              <Pressable
                style={{
                  backgroundColor: '#007AFF',
                  padding: 12,
                  borderRadius: 8,
                  alignItems: 'center',
                }}
                onPress={() => setCounter(counter + 1)}>
                <Text style={{ color: 'white', fontWeight: '600' }}>Increment</Text>
              </Pressable>
            </View>
          </RNHostView>
        </Popover.Content>
      </Popover>
    </Host>
  );
}
```

## API

```tsx
import { RNHostView } from '@expo/ui/swift-ui';
```

## Component

### `RNHostView`

Supported platforms: iOS, tvOS.

Type: React.[Element](https://www.typescriptlang.org/docs/handbook/jsx.html#function-component)<[RNHostViewProps](#rnhostviewprops)\>

RNHostViewProps

### `children`

Supported platforms: iOS, tvOS.

Type: `React.ReactElement`

The RN View to be hosted.

### `matchContents`

Supported platforms: iOS, tvOS.

Optional • Type: `boolean` • Default: `false`

When `true`, the RNHost will update its size in the React Native view tree to match the children's size. When `false`, the RNHost will use the size of the parent SwiftUI View. Can be only set once on mount.
