Appearance
Tectly Editor Widget
The widget embeds our floor plan editor into your web page so your users can review and edit the geometry Tectly extracts. It renders as an iframe inside a container of your choice on your site.
The widget loads a single Tectly project. Whether to upload a floor plan to that project from your backend before mounting is up to you — users will land directly on the editor. Otherwise the widget prompts the user to upload a plan themselves.
Call widget.save() to persist the current state of the floor plan back to Tectly.
Installation
sh
npm i @tectly/widgetOr via CDN — the package exposes a TectlyWidget global:
html
<script src="https://unpkg.com/@tectly/widget"></script>Quick start
html
<div id="tectly-container"></div>ts
import { TectlyWidget } from "@tectly/widget";
const widget = new TectlyWidget({
projectId: "my-project-id",
token: "my-project-scoped-session-token",
});
widget.start("#tectly-container");Authentication
The widget authenticates with a project-scoped session token that you can issue from your backend. Tokens are valid for 12 hours.
sh
curl -X POST https://platform.tectly.com/projects/{id}/issue-session-token \
-H "Authorization: Bearer <your-account-token>"WARNING
Never pass your account bearer token to the client. It can access every project in your account. Always issue a project-scoped session token server-side.
Integration flow
Configuration
| Option | Type | Required | Description |
|---|---|---|---|
projectId | string | Yes | The id of the project to load. |
token | string | Yes | A project-scoped session token. See Authentication. |
environmentUrl | string | No | The Tectly environment. Defaults to https://sandbox.platform.tectly.com. Use https://platform.tectly.com for production. |
origin | string | No | Override the parent origin used to validate postMessage traffic. Defaults to window.location.origin; only set this if the parent's effective origin differs (e.g. nested iframes or a reverse proxy). |
API
start(container: string | HTMLElement)— mount the editor iframe intocontainer, given as a CSS selector or DOM element. Callingstart()twice on the same instance is a no-op and logs a warning.destroy()— remove the iframe, tear down the message bridge, and clear all event listeners.save()— ask the editor to persist the current floor plan. Resolves via thesavedevent; only call onceconnectedhas fired.on(event, callback)/off(event, callback)— subscribe or unsubscribe from events.
You can mount multiple widget instances on the same page — each owns its own iframe and message channel.
Events
| Event | Payload | Description |
|---|---|---|
connected | — | The editor has loaded and is ready to receive commands. |
saved | { success: boolean } | Emitted after a save() call completes. |
ts
widget.on("connected", () => console.log("Editor ready."));
widget.on(
"saved",
({ success }) => success && console.log("Floor plan saved."),
);TypeScript
The package ships its own type definitions. The full public surface:
ts
type EventCallback = (...args: any[]) => void;
interface TectlyWidgetOptions {
projectId: string;
token: string;
environmentUrl?: string;
origin?: string;
}
class TectlyWidget {
constructor(options: TectlyWidgetOptions);
start(container: string | HTMLElement): void;
destroy(): void;
save(): void;
on(event: string, callback: EventCallback): void;
off(event: string, callback: EventCallback): void;
}Framework examples
ts
import { TectlyWidget } from "@tectly/widget";
const widget = new TectlyWidget({
projectId: "my-project-id",
token: "my-project-scoped-session-token",
});
widget.start("#tectly-container");
document
.querySelector("#save-button")
?.addEventListener("click", () => widget.save());