Documentation Index
Fetch the complete documentation index at: https://superdoc-nick-sd-2070-add-content-controls-namespace-to-doc.mintlify.app/llms.txt
Use this file to discover all available pages before exploring further.
Complete guide to configuring the template builder component.
Document options
Control which document is loaded and how users interact with it:
<SuperDocTemplateBuilder
document={{
source: string | File | Blob, // Document to load
mode: "editing" | "viewing", // Default: "editing"
}}
/>
Editing mode - Users can edit document content and insert fields.
Viewing mode - Read-only document display, fields can still be inserted.
Field system
Available fields
Define which fields users can insert:
<SuperDocTemplateBuilder
fields={{
available: [
{
id: "1",
label: "Customer Name",
defaultValue: "John Doe",
metadata: { type: "text" },
},
{
id: "2",
label: "Signature",
mode: "block",
fieldType: "signer",
},
],
allowCreate: true,
}}
/>
Field types
Tag fields with a fieldType to distinguish roles:
<SuperDocTemplateBuilder
fields={{
available: [
{ id: "1", label: "Company Name", fieldType: "owner" },
{ id: "2", label: "Signer Name", fieldType: "signer" },
{ id: "3", label: "Date" }, // defaults to "owner"
],
}}
/>
Import the optional CSS to color-code fields in the editor:
import "@superdoc-dev/template-builder/field-types.css";
Customize colors with CSS variables:
:root {
--superdoc-field-owner-color: #629be7;
--superdoc-field-signer-color: #d97706;
}
The fieldType value flows through all callbacks (onFieldInsert, onFieldsChange, onExport, etc.) and is stored in the SDT tag metadata.
Field creation
Allow users to create new fields while building templates:
<SuperDocTemplateBuilder
fields={{
available: myFields,
allowCreate: true,
}}
onFieldCreate={async (field) => {
// field.id starts with "custom_"
// field.fieldType is "owner" or "signer" (user-selected)
// field.mode is "inline" or "block" (user-selected)
const savedField = await api.createField(field);
// Return updated field or void
return { ...field, id: savedField.id };
}}
/>
When enabled, the field menu shows a “Create New Field” option with inputs for name, mode (inline/block), and field type (owner/signer).
Linked fields
When a user selects an existing field from the “Existing Fields” section in the menu, a linked copy is inserted. Both instances share a group ID and stay in sync.
The menu automatically groups existing fields and shows the count. When the last field in a group is deleted, the remaining field’s group tag is removed.
Trigger pattern
Change what opens the field insertion menu:
<SuperDocTemplateBuilder
menu={{
trigger: "@@", // Now type @@ instead of {{
}}
/>
Replace the default field menu entirely:
function CustomMenu({
isVisible,
position,
filteredFields,
filterQuery,
existingFields,
allowCreate,
onSelect,
onSelectExisting,
onClose,
}) {
if (!isVisible) return null;
return (
<div style={{ position: "fixed", left: position?.left, top: position?.top }}>
{filterQuery && <div>Searching: {filterQuery}</div>}
{existingFields?.length > 0 && (
<div>
<h4>Existing fields</h4>
{existingFields.map((field) => (
<button key={field.id} onClick={() => onSelectExisting?.(field)}>
{field.alias} {field.fieldType && `[${field.fieldType}]`}
</button>
))}
</div>
)}
<h4>Available fields</h4>
{filteredFields.map((field) => (
<button key={field.id} onClick={() => onSelect(field)}>
{field.label} {field.fieldType && `(${field.fieldType})`}
</button>
))}
<button onClick={onClose}>Close</button>
</div>
);
}
<SuperDocTemplateBuilder menu={{ component: CustomMenu }} />;
The component handles trigger detection, filtering, and positioning. You render the UI.
Position and visibility
<SuperDocTemplateBuilder
list={{
position: "left" | "right",
}}
/>
Omit list prop entirely to hide the sidebar.
Custom list component
Replace the default sidebar:
function CustomFieldList({ fields, onSelect, onDelete, selectedFieldId }) {
return (
<aside>
<h3>Template Fields ({fields.length})</h3>
{fields.map((field) => (
<div
key={field.id}
onClick={() => onSelect(field)}
style={{
background: selectedFieldId === field.id ? "#e3f2fd" : "white",
}}
>
<strong>{field.alias}</strong>
{field.fieldType && <span> [{field.fieldType}]</span>}
{field.group && <span> (grouped)</span>}
<button
onClick={(e) => {
e.stopPropagation();
onDelete(field.id);
}}
>
Delete
</button>
</div>
))}
</aside>
);
}
<SuperDocTemplateBuilder
list={{
position: "right",
component: CustomFieldList,
}}
/>;
Control the document editing toolbar:
// Boolean — render default toolbar container
<SuperDocTemplateBuilder toolbar={true} />
// String — mount into an existing element
<SuperDocTemplateBuilder toolbar="#my-toolbar" />
// Object — full control
<SuperDocTemplateBuilder
toolbar={{
selector: "#my-toolbar",
toolbarGroups: ["center"],
excludeItems: ["italic", "bold"],
}}
/>
Event handlers
Field lifecycle events
<SuperDocTemplateBuilder
onFieldInsert={(field) => {
console.log("Inserted:", field.alias, field.fieldType);
}}
onFieldUpdate={(field) => {
console.log("Updated:", field.alias);
}}
onFieldDelete={(fieldId) => {
console.log("Deleted:", fieldId);
}}
onFieldsChange={(fields) => {
console.log("Template has", fields.length, "fields");
const signerFields = fields.filter((f) => f.fieldType === "signer");
console.log("Signer fields:", signerFields.length);
}}
/>
Selection and interaction
<SuperDocTemplateBuilder
onFieldSelect={(field) => {
if (field) {
console.log("Selected:", field.alias, field.fieldType);
}
}}
onTrigger={(event) => {
console.log("Trigger at:", event.position);
console.log("Bounds:", event.bounds);
}}
/>
Export event
<SuperDocTemplateBuilder
onExport={(event) => {
console.log("Exported", event.fields.length, "fields");
console.log("File:", event.fileName);
// event.blob is available when triggerDownload: false
}}
/>
Document ready
<SuperDocTemplateBuilder
onReady={() => {
console.log("Document loaded and ready");
}}
/>
Telemetry
Telemetry is enabled by default with source: 'template-builder' metadata. You can override or extend the defaults:
<SuperDocTemplateBuilder
licenseKey="your-license-key"
telemetry={{
enabled: true,
metadata: { source: "my-app", environment: "production" },
}}
/>
To disable telemetry:
<SuperDocTemplateBuilder telemetry={{ enabled: false }} />
For more details on how telemetry works, see the Telemetry page.
License key
Pass licenseKey to identify your organization in telemetry:
<SuperDocTemplateBuilder licenseKey="your-license-key" />
The key is used solely for organization identification. It does not enable or disable any features, and nothing is blocked if a usage quota is reached. The key is forwarded to the underlying SuperDoc instance.
Complete example
Putting it all together:
import { useState, useRef } from "react";
import SuperDocTemplateBuilder from "@superdoc-dev/template-builder";
import type {
SuperDocTemplateBuilderHandle,
FieldDefinition,
} from "@superdoc-dev/template-builder";
import "superdoc/style.css";
import "@superdoc-dev/template-builder/field-types.css";
function TemplateEditor() {
const builderRef = useRef<SuperDocTemplateBuilderHandle>(null);
const [fields, setFields] = useState<FieldDefinition[]>([
{ id: "1", label: "Customer Name" },
{ id: "2", label: "Customer Email" },
{ id: "3", label: "Invoice Date" },
{ id: "4", label: "Total Amount" },
{ id: "5", label: "Signer Name", fieldType: "signer" },
{ id: "6", label: "Signature", mode: "block", fieldType: "signer" },
]);
const handleExport = async () => {
await builderRef.current?.exportTemplate({
fileName: "invoice-template",
});
};
const handleFieldCreate = async (field: FieldDefinition) => {
const saved = await fetch("/api/fields", {
method: "POST",
body: JSON.stringify(field),
}).then((r) => r.json());
setFields((prev) => [...prev, { ...field, id: saved.id }]);
return { ...field, id: saved.id };
};
return (
<div>
<header>
<h1>Invoice Template Builder</h1>
<button onClick={handleExport}>Export Template</button>
</header>
<SuperDocTemplateBuilder
ref={builderRef}
document={{
source: "invoice-base.docx",
mode: "editing",
}}
fields={{
available: fields,
allowCreate: true,
}}
list={{ position: "right" }}
toolbar={true}
onFieldsChange={(templateFields) => {
console.log("Template updated:", templateFields);
}}
onFieldCreate={handleFieldCreate}
onExport={(event) => {
console.log("Exported", event.fields.length, "fields");
}}
/>
</div>
);
}
Styling
The component uses CSS classes you can target:
.superdoc-template-builder {
height: 100vh;
}
.superdoc-field-menu {
border: 1px solid #ccc;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
}
.superdoc-field-list {
background: #f5f5f5;
border-left: 1px solid #ddd;
}
Import superdoc/style.css for proper rendering. Optionally import @superdoc-dev/template-builder/field-types.css for field type color-coding.