Content controls are Word’s native primitive for stable, identity-bearing regions inside a document. They survive Word round-trips, carry app-defined metadata in aDocumentation Index
Fetch the complete documentation index at: https://superdoc-caio-toolbar-formatting-marks-button-opt-in.mintlify.app/llms.txt
Use this file to discover all available pages before exploring further.
tag string, and can be discovered, updated, locked, or replaced from any surface that drives SuperDoc: the browser editor, the Node SDK, the CLI, an MCP tool, an AI agent.
In OOXML they are w:sdt elements (structured document tags). SuperDoc exposes the full surface under editor.doc.contentControls.* and editor.doc.create.contentControl.
Two patterns to start
Smart fields: one value, every occurrence
Wrap every occurrence of a template variable in an inline text content control sharing the sametag. Select by tag, then push the same value to each matching control.
examples/document-api/content-controls/tagged-inline-text.
Reusable sections: tagged blocks that know their version
Encode{ sectionId, version } in the tag of a block content control. The app reads the live version from contentControls.list and offers an in-place update when the document falls behind the section library.
demos/contract-templates.
Why tag, not nodeId
Two channels of identity exist on a content control:
| Channel | Source | Stable across loads | Stable through Word edits |
|---|---|---|---|
nodeId | SuperDoc-assigned at parse time | Best-effort | No |
tag | App-defined, written to OOXML <w:tag w:val="..."> | Yes | Yes (Word preserves the SDT and its tag) |
nodeId for in-session targeting. Use tag for durable identity that survives DOCX round-trips, including documents edited in Word and reopened. JSON-encode the tag when you need to carry structured metadata (kind, version, owner, group).
Cross-surface: same operations everywhere
Document API content controls are not editor-specific. The same operation IDs are available on every surface that drives SuperDoc.| Surface | Binding |
|---|---|
| Browser editor | editor.doc.contentControls.* |
| Node SDK | bound document handle methods |
| CLI | superdoc commands |
| MCP / AI tools | tool wrappers around the same operation IDs |
When to use Template Builder vs Document API
Two valid paths. Both build on Word content controls.| Use Template Builder when | Use Document API content controls when |
|---|---|
| You’re building in React and want a packaged authoring component | You’re on vanilla JS, Vue, Angular, or any non-React stack |
You want the {{ trigger menu, field sidebar, linked field groups, and DOCX export wired up out of the box | You need a custom UX (your own field menu, your own sidebar) |
| Owner/signer field types and inline custom field creation match your workflow | You’re operating headless: server-side jobs, AI agents, CLI scripts |
| You want a shorter path to a working template authoring UI | You need runtime updates against existing tagged regions (smart fields, version-aware section swaps) |
Operation reference at a glance
| Concept | Operation |
|---|---|
| Create a control around a range | editor.doc.create.contentControl |
| Wrap an existing range | editor.doc.contentControls.wrap |
| Find by tag | editor.doc.contentControls.selectByTag |
| Find by alias | editor.doc.contentControls.selectByTitle |
| List all controls | editor.doc.contentControls.list |
| Inspect one | editor.doc.contentControls.get |
| Update text value | editor.doc.contentControls.text.setValue |
| Replace whole content | editor.doc.contentControls.replaceContent |
| Patch metadata (tag, alias, appearance) | editor.doc.contentControls.patch |
| Set lock mode | editor.doc.contentControls.setLockMode |
| Delete (with content) | editor.doc.contentControls.delete |
| Unwrap (keep content) | editor.doc.contentControls.unwrap |
Read sdtPr directly | editor.doc.contentControls.getRawProperties |
Edit sdtPr directly | editor.doc.contentControls.patchRawProperties |
text.*, date.*, checkbox.*, choiceList.* (combo/dropdown), repeatingSection.*, and group.*. See the reference index for the full catalog.
Lock modes
SetlockMode when you create a control to govern which changes are allowed.
| Mode | Behavior |
|---|---|
unlocked | Content and properties can be updated through the Document API. |
sdtLocked | The wrapper is preserved through user edits. |
contentLocked | The content can’t be modified through the editor surface. |
sdtContentLocked | Both wrapper and content are preserved. |
text.setValue, replaceContent, or patch, use lockMode: 'unlocked'.
Data binding
Content controls can carry an OOXML<w:dataBinding> link to a custom XML data part. Read and write the binding metadata with contentControls.getBinding, setBinding, and clearBinding. The binding survives DOCX round-trips.
For runtime synchronization with backing data, drive the control directly with text.setValue or replaceContent.
Replacing content
contentControls.replaceContent accepts plain text. For richer fragments (paragraphs with formatting, tables, lists), use doc.insert to place the content, then create.contentControl({ at: range, ... }) to wrap the inserted range with a tag.
Next steps
Tagged inline text example
The smallest content-control workflow.
create.contentControl + selectByTag + text.setValue.Contract templates demo
Smart fields and versioned sections composed into one runtime app.
Template Builder
Ready-made React authoring component for content-control templates.
Reference: all operations
Every
contentControls.* operation with input, output, and failure codes.
