Skip to content

React Native

Status: Experimental

Support for React Native is new, and as such the API is not final and might not cover various use cases. It also might be buggy so consider this a very early alpha.

Please visit the GitHub and contribute to the discussions!

npm install @floating-ui/react-native

Usage

The useFloating() hook accepts all of computePosition's options excluding strategy.

import {View, Text} from 'react-native';
import {useFloating, shift} from '@floating-ui/react-native';
 
function App() {
  const {x, y, reference, floating} = useFloating({
    placement: 'right',
    middleware: [shift()],
  });
 
  return (
    <View>
      <View ref={reference}>
        <Text>Reference</Text>
      </View>
      <View
        ref={floating}
        style={{
          position: 'absolute',
          top: y ?? 0,
          left: x ?? 0,
        }}
      >
        <Text>Floating</Text>
      </View>
    </View>
  );
}

x and y will be null initially, before the layout effect has fired.

useFloating() only calculates the position once on render, or when the reference/floating elements changed. Depending on the context in which the floating element lives, you'll likely need to update its position in an effect. See Updating.

External reference

As reference is a callback ref, you can call it with your external reference element:

function MyComponent({triggerRef}) {
  const {reference} = useFloating();
 
  useLayoutEffect(() => {
    reference(triggerRef.current);
  }, [triggerRef.current]);
 
  // You may need to disable the React Hooks ESLint rule for the
  // dependency array.
}

Internal refs

const {refs} = useFloating();

If another library's hook requires a ref passed to it, you can do so:

const {refs} = useFloating();
const otherLib = useOtherLib({
  ref: refs.floating, // or refs.reference
});

The reference and floating values returned from the hook are callback refs. Only pass them to an element's ref prop.

ScrollView

When your floating element is portaled to the app root, while the reference element is inside a <ScrollView />, you pass the sameScrollView option, and spread scrollProps to the component:

import {View, Text, ScrollView} from 'react-native';
import {useFloating} from '@floating-ui/react-native';
 
function App() {
  const {x, y, reference, floating, scrollProps} = useFloating({
    placement: 'right',
    sameScrollView: false,
  });
 
  return (
    <View>
      <ScrollView {...scrollProps}>
        <View ref={reference}>
          <Text>Reference</Text>
        </View>
      </ScrollView>
 
      <View
        ref={floating}
        style={{
          position: 'absolute',
          top: y ?? 0,
          left: x ?? 0,
        }}
      >
        <Text>Floating</Text>
      </View>
    </View>
  );
}

offsetParent

Pass this to the floating element's offsetParent, if required:

import {View, Text, ScrollView} from 'react-native';
import {useFloating} from '@floating-ui/react-native';
 
function App() {
  const {x, y, reference, floating, offsetParent} = useFloating({
    placement: 'right',
    sameScrollView: false,
  });
 
  return (
    <View>
      <ScrollView>
        <View ref={reference}>
          <Text>Reference</Text>
        </View>
      </ScrollView>
 
      <View ref={offsetParent}>
        <View
          ref={floating}
          style={{
            position: 'absolute',
            top: y ?? 0,
            left: x ?? 0,
          }}
        >
          <Text>Floating</Text>
        </View>
      </View>
    </View>
  );
}

Updating

The hook returns an update() function to update the position:

const {update} = useFloating();

In addition, the refs containing the actual elements are passed back:

const {refs} = useFloating();
 
// .current will be filled with the element inside an effect
// refs.reference.current
// refs.floating.current
// refs.offsetParent.current

Arrow

A ref can be passed as the element:

import {useRef} from 'react';
import {useFloating, arrow} from '@floating-ui/react-native';
 
function App() {
  const arrowRef = useRef();
  const {
    x,
    y,
    middlewareData: {arrow: {x: arrowX, y: arrowY} = {}},
  } = useFloating({
    middleware: [arrow({element: arrowRef})],
  });
 
  // Pass the `arrowRef` to the element
}

Conditional rendering

If you're conditionally rendering the arrow element (not just the floating element), you'll want to utilize the same technique as the reference and floating elements which is a callback function that calls update() after assigning the ref value.

<View
  ref={(node) => {
    arrowRef.current = node;
    update();
  }}
/>