> ## Documentation Index
> Fetch the complete documentation index at: https://superdoc-caio-pizzol-docs-ai-core-preset.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# Configuration Options

Complete guide to configuring the template builder component.

## Document options

Control which document is loaded and how users interact with it:

```tsx theme={null}
<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.

Changing `mode` at runtime switches between editing and viewing without recreating the editor: no scroll jump or content flash:

```tsx theme={null}
<SuperDocTemplateBuilder
  document={{ source: file, mode: isEditing ? "editing" : "viewing" }}
/>
```

## Field system

### Available fields

Define which fields users can insert:

```tsx theme={null}
<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:

```tsx theme={null}
<SuperDocTemplateBuilder
  fields={{
    available: [
      { id: "1", label: "Company Name", fieldType: "owner" },
      { id: "2", label: "Signer Name", fieldType: "signer" },
      { id: "3", label: "Date" }, // defaults to "owner"
    ],
  }}
/>
```

Color-code fields in the document and sidebar with `fieldColors`:

```tsx theme={null}
<SuperDocTemplateBuilder
  fields={{
    available: [
      { id: "1", label: "Company Name", fieldType: "owner" },
      { id: "2", label: "Signer Name", fieldType: "signer" },
      { id: "3", label: "Effective Date", fieldType: "date" },
    ],
  }}
  fieldColors={{
    owner: "#629be7",
    signer: "#d97706",
    date: "#059669",
  }}
/>
```

Each color controls the field's border and label in the document. The sidebar badges match automatically. Custom field types beyond `owner` and `signer` work the same way: just add them to `fieldColors`.

<Tip>
  You can also import `@superdoc-dev/template-builder/field-types.css` directly and use CSS variables instead. The `fieldColors` prop is the recommended approach: no extra imports needed.
</Tip>

The `fieldType` value flows through all callbacks (`onFieldInsert`, `onFieldsChange`, `onExport`, etc.) and is stored in the SDT tag metadata.

### Preset block content

Use `presetContent` to prefill block fields with a structure such as a table or list:

```tsx theme={null}
<SuperDocTemplateBuilder
  fields={{
    available: [
      {
        id: "sample_table",
        label: "Sample Table",
        mode: "block",
        fieldType: "data",
        lockMode: "contentLocked",
        presetContent: {
          html: "<table style=\"border-collapse: collapse; width: 100%;\"><tr><th style=\"border: 1px solid #000;\">Column A</th><th style=\"border: 1px solid #000;\">Column B</th></tr><tr><td style=\"border: 1px solid #000;\"></td><td style=\"border: 1px solid #000;\"></td></tr></table>",
          // or json: { ...ProseMirror JSON... }
        },
      },
    ],
  }}
/>
```

`presetContent` is passed into the existing block insertion command. For `mode: "inline"` fields, `presetContent` is ignored.

<Note>
  * `presetContent.json` is recommended when you need the most reliable preservation of structure, semantics, and editor-compatible styling.
  * With `presetContent.html`, include required attributes and inline styles explicitly so the HTML parser can map them into node attributes.
</Note>

### Field creation

Allow users to create new fields while building templates:

```tsx theme={null}
<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).

### Field locking

Make fields read-only so end users can't edit their content:

```tsx theme={null}
<SuperDocTemplateBuilder
  defaultLockMode="contentLocked"
  fields={{
    available: [
      { id: "1", label: "Customer Name" },
      { id: "2", label: "Notes", lockMode: "unlocked" }, // this one stays editable
    ],
  }}
/>
```

Per-field `lockMode` overrides `defaultLockMode`. The default field creation form includes a "Locked" checkbox that sets `contentLocked`.

Template authors can always delete and manage fields regardless of lock mode: locking only affects end users interacting with the document. For advanced use cases, see [lock modes](/extensions/structured-content#lock-modes).

### 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.

## Menu customization

### Trigger pattern

Change what opens the field insertion menu:

```tsx theme={null}
<SuperDocTemplateBuilder
  menu={{
    trigger: "@@", // Now type @@ instead of {{
  }}
/>
```

### Custom menu component

Replace the default field menu entirely:

```tsx theme={null}
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.

## List sidebar

### Position and visibility

```tsx theme={null}
<SuperDocTemplateBuilder
  list={{
    position: "left" | "right",
  }}
/>
```

Omit `list` prop entirely to hide the sidebar.

### Custom list component

Replace the default sidebar:

```tsx theme={null}
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,
  }}
/>;
```

## Toolbar configuration

Control the document editing toolbar:

```tsx theme={null}
// 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

```tsx theme={null}
<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

```tsx theme={null}
<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

```tsx theme={null}
<SuperDocTemplateBuilder
  onExport={(event) => {
    console.log("Exported", event.fields.length, "fields");
    console.log("File:", event.fileName);
    // event.blob is available when triggerDownload: false
  }}
/>
```

### Document ready

```tsx theme={null}
<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:

```tsx theme={null}
<SuperDocTemplateBuilder
  licenseKey="your-license-key"
  telemetry={{
    enabled: true,
    metadata: { source: "my-app", environment: "production" },
  }}
/>
```

To disable telemetry:

```tsx theme={null}
<SuperDocTemplateBuilder telemetry={{ enabled: false }} />
```

For more details on how telemetry works, see the [Telemetry](/resources/telemetry) page.

### License key

Pass `licenseKey` to identify your organization in telemetry:

```tsx theme={null}
<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:

```tsx theme={null}
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:

```css theme={null}
.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.
