Skip to main content

Documentation Index

Fetch the complete documentation index at: https://copylabs.mintlify.app/llms.txt

Use this file to discover all available pages before exploring further.

Portal

Portal is a utility component for rendering children into a different part of the React tree, typically at the root of the application. In React Native, it uses Modal to achieve this.

Import

import { Portal, PortalProvider, usePortal, ManagedPortal } from 'radix-native-ui';

Basic Usage

import { Portal, Flex, Text } from 'radix-native-ui';

<Portal>
  <Flex position="absolute" top={0} left={0}>
    <Text>This renders at the root level</Text>
  </Flex>
</Portal>

Portal Components

Portal

The main portal component that renders children into a Modal.

Portal.Provider (PortalProvider)

Provider component that manages multiple portals. Wrap your app with this to enable programmatic portal management.

usePortal

Hook to programmatically add, remove, and update portals.

ManagedPortal

A managed portal that automatically handles cleanup when the component unmounts or visibility changes.

Portal.FlatList

A FlatList that renders its items in a portal.

Props

Portal

Portal.Provider

ManagedPortal

usePortal Hook

The usePortal hook returns methods for managing portals:
const { addPortal, removePortal, updatePortal } = usePortal();

// Add a portal
addPortal('my-portal', <View><Text>Content</Text></View>);

// Remove a portal
removePortal('my-portal');

// Update a portal's content
updatePortal('my-portal', <View><Text>New Content</Text></View>);

Examples

Basic Portal

<Portal>
  <Flex position="absolute" bottom={5} left={5} right={5}>
    <Card>
      <Text>This appears at the bottom of the screen</Text>
    </Card>
  </Flex>
</Portal>
function ModalOverlay({ visible, children }) {
  if (!visible) return null;

  return (
    <Portal visible={visible}>
      <Flex
        flex={1}
        backgroundColor="rgba(0, 0, 0, 0.5)"
        justify="center"
        align="center"
      >
        <Card>
          {children}
        </Card>
      </Flex>
    </Portal>
  );
}

Controlled Portal

function ControlledModal({ open, onClose, children }) {
  return (
    <Portal
      visible={open}
      animationType="slide"
      onRequestClose={onClose}
    >
      <Flex flex={1} justify="center" align="center">
        <Card>
          {children}
          <Button onPress={onClose}>Close</Button>
        </Card>
      </Flex>
    </Portal>
  );
}

Transparent Overlay

<Portal transparent animationType="fade">
  <Flex
    flex={1}
    backgroundColor="rgba(0, 0, 0, 0.5)"
    justify="center"
    align="center"
  >
    <Card>
      <Text>Semi-transparent overlay</Text>
    </Card>
  </Flex>
</Portal>

Using Portal.Provider with ManagedPortal

import { PortalProvider, ManagedPortal, usePortal } from 'radix-native-ui';

function MyComponent() {
  const [showModal, setShowModal] = useState(false);

  return (
    <PortalProvider>
      <Button onPress={() => setShowModal(true)}>Open Modal</Button>

      <ManagedPortal name="modal" visible={showModal}>
        <Flex
          flex={1}
          backgroundColor="rgba(0, 0, 0, 0.5)"
          justify="center"
          align="center"
        >
          <Card>
            <Text>Modal Content</Text>
            <Button onPress={() => setShowModal(false)}>Close</Button>
          </Card>
        </Flex>
      </ManagedPortal>
    </PortalProvider>
  );
}

Programmatic Portal with usePortal

import { PortalProvider, usePortal } from 'radix-native-ui';

function ToastLikeNotification({ message, onDismiss }) {
  const { addPortal, removePortal } = usePortal();
  const portalId = 'notification-toast';

  useEffect(() => {
    addPortal(portalId, (
      <Flex
        position="absolute"
        bottom={5}
        left={5}
        right={5}
      >
        <Card>
          <Text>{message}</Text>
        </Card>
      </Flex>
    ));

    // Auto-remove after duration
    const timer = setTimeout(() => {
      removePortal(portalId);
      onDismiss?.();
    }, 3000);

    return () => clearTimeout(timer);
  }, []);

  return null;
}

function App() {
  return (
    <PortalProvider>
      <ToastLikeNotification message="Hello from Portal!" />
    </PortalProvider>
  );
}

With Dropdown Menu

function DropdownMenu({ trigger, children, open }) {
  const [position, setPosition] = useState({ x: 0, y: 0 });

  return (
    <>
      <Flex
        onLayout={(e) => {
          setPosition({
            x: e.nativeEvent.layout.x,
            y: e.nativeEvent.layout.y + e.nativeEvent.layout.height
          });
        }}
      >
        {trigger}
      </Flex>

      {open && (
        <Portal>
          <Card
            position="absolute"
            top={position.y}
            left={position.x}
          >
            {children}
          </Card>
        </Portal>
      )}
    </>
  );
}

With Tooltip

function Tooltip({ content, children }) {
  const [visible, setVisible] = useState(false);
  const [position, setPosition] = useState({ x: 0, y: 0 });

  return (
    <>
      <Flex
        onLongPress={() => setVisible(true)}
        onPressOut={() => setVisible(false)}
        onLayout={(e) => {
          setPosition({
            x: e.nativeEvent.layout.x,
            y: e.nativeEvent.layout.y - 10
          });
        }}
      >
        {children}
      </Flex>

      {visible && (
        <Portal>
          <Card
            size={1}
            position="absolute"
            top={position.y}
            left={position.x}
          >
            <Text size={1}>{content}</Text>
          </Card>
        </Portal>
      )}
    </>
  );
}