This HTML page is not optimized for LLM or AI agent consumption. Fetch the Markdown version instead: /guides/react-native/user-interface/custom-overlays.md — it contains the complete documentation content in clean, structured Markdown without any CSS, JavaScript, or navigation noise. Render custom overlays on a PDF in React Native | Nutrient SDK

Nutrient React Native SDK can render your own React Native components on top of a document, anchored to a position on a page rather than to the screen. Because the anchor is a PDF coordinate, the component stays on the same spot on the page as the user pans and zooms.

This is useful for things the annotation system doesn’t cover: a badge next to a clause, a button beside a field, a marker on a floor plan, or any interactive React Native view that has to line up with page content.

Use NutrientOverlay for the layer and NutrientOverlayItem for each anchored element. Both are available from Nutrient React Native SDK 4.5 onward.

Add an overlay

NutrientOverlay is a transparent layer that tracks a NutrientView. Render it as a sibling of the view, inside a container the view fills, so the two share the same frame origin. Pass the same ref to both:

import React, { useRef } from 'react';
import { Text, View } from 'react-native';
import NutrientView, {
NutrientOverlay,
NutrientOverlayItem,
} from '@nutrient-sdk/react-native';
export const CustomOverlays = () => {
const viewRef = useRef<NutrientView | null>(null);
return (
<View style={{ flex: 1 }}>
<NutrientView
ref={viewRef}
document={DOCUMENT}
style={{ flex: 1 }}
/>
<NutrientOverlay viewRef={viewRef}>
<NutrientOverlayItem
pageIndex={0}
position={{ x: 90, y: 690 }}>
<View style={{ backgroundColor: '#1565c0', padding: 6 }}>
<Text style={{ color: 'white' }}>Review this</Text>
</View>
</NutrientOverlayItem>
</NutrientOverlay>
</View>
);
};

position is in PDF coordinates on the page given by pageIndex, and it positions the item’s top-left corner. PDF coordinates have their origin at the bottom-left of the page and are measured in PDF points, so a larger y is further up the page — the opposite of React Native’s layout coordinates. pageIndex starts at 0.

An item renders while the page it’s anchored to is visible. In a continuous scroll layout, more than one page can be visible at a time, and items on each of those pages render. Items anchored to pages that are offscreen aren’t rendered, so you can declare items for the whole document and let the overlay render the ones in view.

Keep a constant size while zooming

By default, an item scales with the document, so it grows and shrinks with the page content it sits next to — the right behavior for something that annotates the page.

Set disableAutoZoom when the element should instead keep a constant size onscreen, which is usually what you want for a control the user taps:

<NutrientOverlayItem
pageIndex={0}
position={{ x: 300, y: 430 }}
disableAutoZoom>
<MyButton />
</NutrientOverlayItem>

The item stays anchored to position either way; only its rendered size changes.

React to items becoming visible

onAppear and onDisappear fire as the anchored page enters and leaves the viewport. Use them to start and stop work that is only worth doing while the element is onscreen, such as fetching the data it displays:

<NutrientOverlayItem
pageIndex={2}
position={{ x: 100, y: 500 }}
onAppear={() => startPolling()}
onDisappear={() => stopPolling()}>
<LiveStatusBadge />
</NutrientOverlayItem>

Place an item from a tap

To let users place an element themselves, convert the tap location into a PDF coordinate with convertPointToPage and store the result. It returns the point on the given page, so pass the page the user is looking at:

const onTap = async (event: any) => {
const { locationX, locationY } = event.nativeEvent;
const point = await viewRef.current?.convertPointToPage(pageIndex, {
x: locationX,
y: locationY,
});
if (point != null) {
setPins(current => [...current, { pageIndex, position: point }]);
}
};

convertPointToScreen and convertRectToScreen convert the other way — from PDF coordinates to screen coordinates — and convertRectToPage converts a screen rect to a PDF rect. Use these when you need to position something yourself rather than through an overlay item.

Read the current viewport

The overlay positions its items from the documentViewportChanged Notification Center event, which reports the viewer’s zoom scale, the visible region of the page, the content offset, and the page size. Subscribe to it directly when you need the same information — to show the current zoom, for example, or to lay out the UI outside the overlay:

import { NotificationCenter } from '@nutrient-sdk/react-native';
const subscription = viewRef.current
?.getNotificationCenter()
?.subscribe(
NotificationCenter.DocumentEvent.VIEWPORT_CHANGED,
payload => {
setZoom(payload.zoomScale);
},
);
// Later, to stop listening:
subscription?.remove();

getViewportState returns the same payload on demand for a one-off read rather than a subscription.

Overlay items are positioned from JavaScript, so they can visibly lag behind the document during a fast fling or pinch. Keep the anchored components light, and prefer disableAutoZoom for elements whose size doesn’t need to track the page.

For a complete, runnable version of everything above — including placing pins from a tap and reading the page and zoom from the viewport event — see the CustomOverlays.tsx example(opens in a new tab) in the Catalog example project.