Skip to main content
Element is the unified data structure for “all visible elements” in NOTE/DOC: strokes, titles, links, TextBox elements, geometries, five-star elements, pictures, etc. are all represented as Element, and distinguished by type. This chapter provides a reusable workflow around the following capabilities:

Key Concepts

1) Why call createElement first?

Some fields in Element can be very large (e.g., stroke sample points, pressure points, angle points, contour points). To avoid JS-side memory issues, the SDK uses an “accessor” design:
  • On the RN side you receive an ElementDataAccessor (a reference/handle)
  • Raw point data caching and read/write happen on the native side
Therefore, when creating a new element, it is recommended to call PluginCommAPI.createElement(...) first so the native side can create and initialize the required caches and accessor references, and then fill in the content you want to write on the JS side.

2) Conventions: page and layer

  • page: documentation uses zero-based page numbers (aligned with UI page numbering).
  • layer: in notes, common layers are 0..3. Links/titles must be on the main layer (layer=0), otherwise validation fails. Document files only have a single layer: the main layer.

3) Document limitations

Document files do not allow inserting TextBox elements / titles / links. Forcing insertion will be rejected by validation.

4) Element Caching and Release

Some fields in Element (stroke sample points, pressure points, angle points, contour points, etc.) can hold a large amount of data. Transferring all of it to the RN side at once not only creates memory pressure, but transfer/conversion time also grows noticeably as the data size grows. Because of this, the native side caches each Element by uuid, and the RN side only holds a reference (uuid + accessors), fetching data on demand. Around this cache there is a full create → read → write → release flow: A few things worth noting:
  • Write APIs depend on the cache still existing: insertElements/modifyElements/replaceElements/recognizeElements/convertElement2Sticker/modifyPageElements/insertPageElements/batchUpdatePageElements all require that the passed-in element’s uuid is currently present in the native cache. This is a different check from “the element already exists on the page” (for example, modifyElements requires the target to already exist on that page) — a uuid that can’t be found in the cache is skipped at an earlier stage, before the “does it already exist on the page” check even happens.
  • The cache is not guaranteed to live forever: clearElementCache() only runs when a plugin calls it; the SDK never triggers it automatically on the plugin’s behalf. Conversely, the host environment may also automatically reclaim part or all of the cache under memory pressure, so you shouldn’t assume a uuid stays valid indefinitely — release elements as soon as you’re done with them.
  • This is a different, coarser-grained cache than ElementDataAccessor: large point fields such as angles/contoursSrc add another on-demand paging accessor layer on top of the cached Element. The accessor itself also keeps a smaller cache on the RN side — read methods such as get/getRange cache the values they fetch, while write methods such as add/set/setRange automatically clear that cache on success; preload/isCached/getCacheStats/clearCache are also available for manual warm-up, inspection, and clearing. Releasing the whole Element also clears its accessor caches. See ElementDataAccessor for details.
The small cache that ElementDataAccessor keeps on the RN side is different from the native-side Element cache described here; see ElementDataAccessor for the distinction.

Get Page Elements

When you need to read all elements on a page (for display, filtering, editing, copying, etc.), use getElements:
After getElements succeeds, the SDK automatically normalizes element structures and fills in accessors. You can directly read typed fields such as stroke/title/link/textBox/geometry/picture based on type.

Create a New Element

To create a new element that will be inserted into a page, use createElement(type):
The Element returned by createElement includes uuid, and fills required ElementDataAccessor fields based on the element type (e.g., angles/contoursSrc, and stroke.* for stroke elements).

Insert Elements into a Page

After preparing the element array to insert (usually from createElement or copied from existing elements), use insertElements to insert into a target page:
TextBox elements/links/titles can only be operated on the main layer (layer=0). Before insertion, ensure element.layerNum = 0, otherwise validation fails.

Modify Existing Elements

The key constraint is: you can only modify elements that already exist on the page. The SDK checks existence using identifiers (e.g., numInPage). Non-existent elements will not be modified successfully. The safest workflow:
  1. Call getElements to fetch the original element list
  2. Find the target element (e.g., by numInPage or uuid)
  3. Modify fields and pass that element (or a set of elements) to modifyElements
If you need to modify “point data” (e.g., stroke sample points), you usually write via ElementDataAccessor.set/setRange on the native side instead of replacing JS arrays directly.

Replace All Elements on a Page

Use replaceElements when you want to “clear all existing elements and replace the page with a new set”. Common scenarios: full-page re-layout, batch import, or writing edited results in one shot.
replaceElements clears existing elements first and then writes the new set. If you expose this in your UI, consider adding a confirmation step or an undo strategy.