Keep widget annotation dimensions consistent across devices
When using custom renderers for widget annotations, their size and position may appear correct on desktop but become incorrect — shrinking, stretching, or overlapping — when viewed on mobile or smaller screens. This happens because the HTML elements don’t automatically adjust as the screen or zoom changes.
Common symptoms include:
- Widget annotations shift or overlap in mobile or responsive views.
- The
noZoomflag has no effect in zoomed-out or responsive modes. - Form fields appear distorted when switching between devices.
While this guide focuses on widget annotations (form fields), the same issue can occur with any annotation type using custom renderers. The solution applies to all custom-rendered annotations.
Root cause
When using custom renderers for widget annotations in Nutrient Web SDK, the rendered HTML elements don’t automatically adjust their width and height in response to viewport or zoom changes.
The Web SDK manages size and position for built-in annotations, but custom renderers must actively handle scaling and resizing for responsive UIs. This leads to inconsistent display of form fields on different screen sizes or when zooming.
Solution
Implement dynamic width and height for HTML elements in your custom renderers. Set display: block on your custom annotation elements because input elements have display: inline-block by default, which can prevent percentage-based width and height from working correctly in the annotation container.
The following example demonstrates how to create a custom renderer with dynamic sizing that responds to zoom changes:
let globalInstance = null;NutrientViewer.load({ ...baseOptions, theme: NutrientViewer.Theme.DARK, customRenderers: { Annotation: ({ annotation }) => { // Only apply custom rendering to widget annotations. if (annotation instanceof NutrientViewer.Annotations.WidgetAnnotation) { const node = document.createElement("input"); node.style.display = "block";
// Set initial dimensions. // The custom renderer receives the annotation in page coordinates, // which are already scaled by zoom, so we use the dimensions directly. node.style.width = "100%"; node.style.height = "100%";
return { node, append: true }; }
// Use default rendering for other annotation types. return null; }, },}).then((instance) => { globalInstance = instance;
// Listen for zoom changes and trigger rerendering. instance.addEventListener("viewState.zoom.change", () => { instance.setViewState(instance.viewState); });});Ensure you recalculate width and height when the viewport, page size, or zoom changes. For a working demo and reference code, refer to the custom renderer — dynamic input fields playground.
Additional considerations
When implementing dynamic sizing for widget annotations, keep the following in mind:
- If the issue persists after adding dynamic sizing, ensure you’re not using any direct DOM injection or unsupported overlay patterns.
- Check that your code for handling form field rendering is triggered after every zoom or resize event.
- If exporting annotated PDFs for debugging, use the download or export feature in the playground to ensure you’re retaining widget annotation data.
- If the annotation content is rasterized (converted to images), size shifting won’t be visible but is still a concern for live widgets.
- Default toolbar configuration typically works. Discrepancies appear mainly with custom renderer logic.
- Always test changes in both desktop and mobile or responsive modes — manually or using browser developer tools.
For more information on custom renderers, refer to the annotation customization guide.