You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
@@ -23,11 +23,12 @@ Importantly, this allows you to continue leveraging Label Studio's annotation ma
23
23
| name | string | — | Unique identifier for the tag (required) |
24
24
|[toName]| string | — | If this is a [self-referencing tag](#Self-referencing-tag), this parameter is required and should match `name`|
25
25
|[data]| string | — | The [task data](#Data-parameter), e.g., `data="$image"` or `data="$text"`|
26
-
|[src]| string | — | URL to an external JavaScript file containing the React component code. Use this as an alternative to inline code. [See more below](#Using-the-src-attribute)|
27
26
|[inputs]| string | — | Defines the JSON schema for the input data (`data`) |
28
27
|[outputs]| string | — | Defines the JSON schema for the [output](#Using-the-outputs-parameter)|
28
+
|[src]| string | — | URL to an external app to load inside the iframe (see [External app mode](#External-app-mode-src)). Supports task data interpolation, e.g. `src="$app_url"`|
29
29
|[style]| string | — | Inline styles or CSS string for the iframe container |
30
30
|[classname]| string | — | Additional CSS classes for the wrapper |
31
+
|[allow]| string | — | iframe permissions policy, e.g. `allow="microphone *; camera *"`|
31
32
32
33
## ReactCode tag usage notes
33
34
@@ -67,37 +68,7 @@ function MyComponent({ React, addRegion, regions, data }) {
67
68
}
68
69
```
69
70
70
-
### Using the `src` attribute
71
71
72
-
By default, you write your React component code inline, directly inside the `<ReactCode>` tag (typically wrapped in a [CDATA section](#CDATA-wrapper)). The `src` attribute provides an alternative approach: instead of embedding the code in the labeling configuration, you can host it at an external URL and reference it.
73
-
74
-
This works similarly to how a `<script src="...">` tag loads JavaScript from an external file in HTML.
The external JavaScript file should export a function component with the same signature as inline code (receiving `React`, `addRegion`, `regions`, `data`, and `viewState` as props).
91
-
92
-
**When to use `src`:**
93
-
94
-
- Your component code is large or complex and difficult to manage inside XML
95
-
- You want to version and maintain your UI code in a separate repository
96
-
- You want to reuse the same component across multiple labeling projects
97
-
- You prefer developing in a standard IDE workflow (edit, deploy, reference)
98
-
99
-
!!! note
100
-
When the `src` attribute is provided, any inline code inside the `<ReactCode>` tag is ignored. The component is loaded entirely from the external URL.
101
72
102
73
## React usage notes
103
74
@@ -144,6 +115,213 @@ You can use:
144
115
-**External CSS**: Load via CDN in your component
145
116
146
117
118
+
## External app mode (`src`)
119
+
120
+
Instead of writing inline React code, you can load a full standalone web application via the `src` parameter. The app can use any framework, build system, or libraries — it is not limited to React. It communicates with Label Studio via `window.postMessage()`.
if (!data) return; // data can be null during pool warm-up
250
+
// Initialize your app with task data, render existing regions
251
+
}
252
+
functionupdateData(data) { /* handle new task data */ }
253
+
functionreconcileRegions(newRegions) {
254
+
regions = newRegions;
255
+
// Reconcile your visual elements with the new regions array
256
+
}
257
+
functionupdateViewState(viewState) { /* e.g. toggle dark mode */ }
258
+
259
+
// Signal readiness — triggers init from Label Studio
260
+
window.parent.postMessage({ type:"ready" }, "*");
261
+
</script>
262
+
</body>
263
+
</html>
264
+
```
265
+
266
+
### Handling null `data`
267
+
268
+
During initialization (and especially with iframe pooling), `data` may be `null` briefly before the real task data arrives. Your app should guard against this:
During development, you need to make your local app accessible to Label Studio (which runs on HTTPS). A local `http://localhost` URL won't work because browsers block HTTP iframes inside HTTPS pages (mixed content).
280
+
281
+
**Step 1: Serve your app locally**
282
+
283
+
```bash
284
+
# From your app directory
285
+
npx serve -l 3000
286
+
```
287
+
288
+
Alternatives: `python3 -m http.server 3000`, `npx http-server -p 3000`, or any dev server (Vite, webpack-dev-server).
289
+
290
+
**Step 2: Expose it via an HTTPS tunnel**
291
+
292
+
```bash
293
+
# In another terminal
294
+
ngrok http 3000
295
+
```
296
+
297
+
ngrok outputs a public HTTPS URL like `https://abc123.ngrok-free.app`. Use that in your config:
Alternatives to ngrok: `cloudflared tunnel --url http://localhost:3000` (Cloudflare Tunnel, no account needed), `npx localtunnel --port 3000`.
304
+
305
+
!!! note
306
+
For production, deploy your app to any static hosting (Vercel, Netlify, S3, GitHub Pages, etc.) and use the permanent HTTPS URL.
307
+
308
+
### Region reconciliation
309
+
310
+
When Label Studio sends a `regions` update, your app must reconcile its visual state. This is the most important pattern for `src` apps:
311
+
312
+
1.**Remove** visuals for regions no longer in the array (deleted)
313
+
2.**Hide** visuals for regions with `hidden: true`
314
+
3.**Create** visuals for new region IDs
315
+
4.**Update** position/value for existing regions that changed
316
+
5.**Focus/highlight** regions with `selected: true`
317
+
318
+
!!! warning Important
319
+
Never modify local state optimistically when adding regions. Always post `addRegion` to the parent and wait for the `regions` update. Label Studio assigns the region ID and is the source of truth.
320
+
321
+
### Handling task and annotation switches
322
+
323
+
When a user switches tasks or annotations, Label Studio may send an `update` message instead of destroying and recreating the iframe. Your app must handle this by reinitializing its state with the new data and regions. Always handle both `init` and `update` message types.
324
+
147
325
## Regions API
148
326
149
327
Your React component receives these props from Label Studio:
@@ -806,6 +984,29 @@ An interface that displays an image and allows adding metadata annotations:
806
984
-->
807
985
```
808
986
987
+
### External app: Map markers (src mode)
988
+
989
+
A Leaflet + OpenStreetMap map where clicking adds markers stored as regions. Uses vanilla JS (no React). The app is loaded via `src`:
0 commit comments