Skip to content

Web Component

<updog-editor> is a custom element that wraps the React editor. Every prop documented in the rest of the reference is available. Set simple values as HTML attributes, and complex ones as JS properties.

import "@updog/data-editor-wc";
import "@updog/data-editor-wc/styles.css";

Defines <updog-editor> globally. Import once, typically at your app entry. Both imports are required. Without the stylesheet the editor renders unstyled.

Vue and Angular also need to be told that updog- tags are custom elements. See Other Frameworks for the per-framework setup.

Use HTML attributes for primitive values. The element observes these and re-renders on change.

Attribute Maps to Type
api-key apiKey string
primary-key primaryKey string
locale locale string
variant variant "editor" | "uploader"
mode mode "modal" | "inline"
open open boolean (presence = true)
rtl rtl boolean
readonly readonly boolean

The primary-key attribute carries a single column. A key built from several columns goes through the primaryKey property or configure(), like every other non-primitive prop.

Set the key one way or the other, never both. The attribute and the property write to the same place, so the later write replaces the earlier one, and a framework template can rewrite the attribute on any re-render.

<updog-editor api-key="your-key" primary-key="id" variant="uploader" readonly></updog-editor>

Everything else, meaning objects, functions, and arrays, is set as a JS property or through configure().

const editor = document.querySelector("updog-editor");
editor.columns = [...];
editor.loadData = async (onChunk) => { ... };
editor.onComplete = async (result) => { ... };

All DataEditorProps fields are valid properties except onClose. See Events.

Sets several properties in one call, typically during setup.

editor.configure({
apiKey: "your-key",
primaryKey: "id",
columns: [...],
loadData: async (onChunk) => onChunk(await fetchRows()),
onComplete: async (result) => { await save(result); },
});

Accepts every prop except onClose. Property updates are batched, so the editor re-renders once per microtask however many properties you set.

Props are merged one level deep. Calling configure() again with the same key replaces that key’s value.

The package ships the same type surface as @updog/data-editor:

import type {
DataEditorColumn,
DataEditorResult,
DataEditorTranslations,
UpdogEditorElement,
} from "@updog/data-editor-wc";
const columns: DataEditorColumn[] = [
{ id: "email", title: "Email", validators: [{ type: "email" }] },
];
const editor = document.querySelector<UpdogEditorElement>("updog-editor")!;
editor.configure({ columns });

UpdogEditorElement is also registered in HTMLElementTagNameMap, so document.querySelector("updog-editor") is typed without the generic.

The custom element takes no generic parameter, unlike the React DataEditor<TRow>. onComplete receives DataEditorResult with rows typed as Record<string, unknown>, so cast to your own row type when you need one.

Open and close the modal. Equivalent to setting open to true / false.

document.getElementById("open-btn").onclick = () => editor.show();

Both are no-ops in mode="inline".

Fires when the user closes the modal (X button or Escape key). It replaces the React onClose prop, dispatched as a CustomEvent.

editor.addEventListener("close", () => editor.hide());

The event bubbles. In mode="inline" it never fires.

Validators are plain objects, so no helper imports are needed:

{ type: "required", message: "Required" }
{ type: "email", message: "Invalid email" }
{ type: "regex", pattern: "^\\+[\\d\\s]+$", message: "Invalid phone" }
{ type: "number", min: 0, max: 100 }
{ type: "oneOf", values: ["A", "B"], message: "Invalid option" }

See Columns for the full list.

<button id="open-btn">Open Editor</button>
<updog-editor id="editor" api-key="your-key" primary-key="id"></updog-editor>
<script type="module">
import "@updog/data-editor-wc";
const editor = document.getElementById("editor");
editor.configure({
columns: [
{ id: "name", title: "Name", validators: [{ type: "required", message: "Required" }] },
{ id: "email", title: "Email", validators: [{ type: "required", message: "Required" }, { type: "email", message: "Invalid" }] },
],
loadData: async (onChunk) => onChunk(await fetch("/api/rows").then(r => r.json())),
onComplete: async (result) => { console.log(result); },
});
document.getElementById("open-btn").onclick = () => editor.show();
editor.addEventListener("close", () => editor.hide());
</script>