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
andfloating
values returned from the hook are callback refs. Only pass them to an element'sref
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();
}}
/>