Skip to main content
Native Word SDT (w:sdt) fields for documents. Supports inline and block structured content tags for dynamic templates with full Word compatibility.

Use case

  • Form templates — Create fillable documents with inline text fields and block content areas
  • Contract generation — Dynamic clauses and terms that map to Word content controls
  • Document automation — Programmatically update specific sections while preserving structure
  • Protected fields — Lock modes control which fields users can edit or delete (ECMA-376 w:lock)

Quick start

// Insert inline field with sdtLocked — users can edit content but not delete the field
editor.commands.insertStructuredContentInline({
  attrs: {
    id: '1',
    alias: 'Customer Name',
    lockMode: 'sdtLocked',
  },
  text: 'John Doe'
});

// Insert a read-only system field
editor.commands.insertStructuredContentInline({
  attrs: {
    id: '3',
    alias: 'Account ID',
    lockMode: 'sdtContentLocked', // fully protected — no edits, no deletion
  },
  text: 'ACC-00042'
});

// Insert block field with sdtLocked — content is editable, wrapper is protected
editor.commands.insertStructuredContentBlock({
  attrs: {
    id: '2',
    alias: 'Terms & Conditions',
    lockMode: 'sdtLocked',
  },
  html: '<p>Please review the terms...</p>'
});

// Update field content
editor.commands.updateStructuredContentById('1', {
  text: 'Jane Smith'
});

// Change lock mode without changing content
editor.commands.updateStructuredContentById('1', {
  attrs: { lockMode: 'contentLocked' }
});

// Get all structured content tags
const allTags = editor.helpers.structuredContentCommands.getStructuredContentTags(editor.state);
console.log(`Document contains ${allTags.length} SDT fields`);

Options

Configure the extension behavior:
structuredContentClass
string
default:"sd-structured-content-block-tag"
CSS class for the block
htmlAttributes
Object
HTML attributes for structured content blocks

Attributes

Node attributes that can be set and retrieved:
id
string
Unique identifier for the structured content block
The id attribute must be a numeric string for valid DOCX output (per ECMA-376 §17.5.2.18). Use Date.now().toString() or sequential integers instead of UUIDs.
tag
string
Content control tag (e.g., ‘block_table_sdt’)
alias
string
default:"Structured content"
Display name for the block
lockMode
StructuredContentLockMode
default:"unlocked"
Controls editing and deletion restrictions on the structured content node. See Lock modes below.

Lock modes

Structured content nodes support four lock modes based on the OOXML w:lock element (ISO/IEC 29500 §17.5.2.23). Lock modes control whether users can edit the content inside a field and whether they can delete the field wrapper itself.
Lock modeWrapperContentUse case
unlockedDeletableEditableDefault — no restrictions
sdtLockedProtectedEditableProtect field structure, allow value changes
contentLockedDeletableRead-onlyDisplay a computed value users can remove
sdtContentLockedProtectedRead-onlyFully protected field (e.g., system-generated ID)
Set the lock mode when inserting:
editor.commands.insertStructuredContentInline({
  attrs: {
    id: '3',
    alias: 'Account ID',
    lockMode: 'sdtContentLocked',
  },
  text: 'ACC-00042',
});
Change the lock mode on an existing field:
editor.commands.updateStructuredContentById('1', {
  attrs: { lockMode: 'contentLocked' },
});
Lock modes round-trip through DOCX. A document with w:lock elements in its SDT properties will import with the correct lock mode and export the w:lock element back to the saved file.

Commands

insertStructuredContentInline

Inserts a structured content inline at the current selection. Example:
editor.commands.insertStructuredContentInline({
  attrs: {
    id: '1',
    alias: 'Customer Name',
    lockMode: 'sdtLocked', // optional, defaults to 'unlocked'
  },
  text: 'John Doe',
});
Parameters:
options
StructuredContentInlineInsert
required

insertStructuredContentBlock

Inserts a structured content block at the current selection. Example:
editor.commands.insertStructuredContentBlock({
  attrs: {
    id: '2',
    alias: 'Terms Section',
    lockMode: 'sdtContentLocked', // optional, defaults to 'unlocked'
  },
  html: '<p>These terms are non-negotiable.</p>',
});
Parameters:
options
StructuredContentBlockInsert
required

updateStructuredContentById

Updates a single structured content field by its unique ID. IDs are unique identifiers, so this will update at most one field. If the updated node does not match the schema, it will not be updated. Pass attrs alone to change attributes (like lockMode) without replacing content: Example:
// Update content
editor.commands.updateStructuredContentById('1', {
  text: 'Jane Smith',
});

// Update lock mode only (preserves content)
editor.commands.updateStructuredContentById('1', {
  attrs: { lockMode: 'contentLocked' },
});

// Update both content and attributes
editor.commands.updateStructuredContentById('1', {
  text: 'New value',
  attrs: { alias: 'Updated Label', lockMode: 'sdtLocked' },
});
Parameters:
id
string
required
Unique identifier of the field
options
StructuredContentUpdate
required

deleteStructuredContent

Removes a structured content. Parameters:
structuredContentTags
Array<any>
required

deleteStructuredContentById

Removes a structured content by ID. Parameters:
idOrIds
string | Array<string>
required

deleteStructuredContentAtSelection

Removes a structured content at cursor, preserving its content.

updateStructuredContentByGroup

Update all structured content fields that share the same group identifier. Example:
editor.commands.updateStructuredContentByGroup('pricing', {
  text: '$99.00'
})
Parameters:
group
string
required
Group identifier to match
options
StructuredContentUpdate
Update options (same as updateStructuredContentById)

deleteStructuredContentByGroup

Remove all structured content fields that share the same group identifier. Example:
editor.commands.deleteStructuredContentByGroup('pricing')
editor.commands.deleteStructuredContentByGroup(['pricing', 'deprecated'])
Parameters:
groupOrGroups
string | Array<string>
required
Group identifier or array of group identifiers

appendRowsToStructuredContentTable

Append multiple rows to the end of a table inside a structured content block. Each inner array represents the cell values for one new row. Example:
editor.commands.appendRowsToStructuredContentTable({
  id: "block-123",
  tableIndex: 0,
  rows: [
    ["A", "B"],
    ["C", "D"],
  ],
  copyRowStyle: true,
});
Parameters:
options
StructuredContentTableAppendRowsOptions
required
Append configuration

Helpers

getStructuredContentBlockTags

Get all block-level structured content tags in the document Example:
const blocks = editor.helpers.structuredContentCommands.getStructuredContentBlockTags(editor.state);
console.log(`Found ${blocks.length} structured content blocks`);
Parameters:
state
any
required

getStructuredContentInlineTags

Get all inline structured content tags in the document Example:
const inlines = editor.helpers.structuredContentCommands.getStructuredContentInlineTags(editor.state);
console.log(`Found ${inlines.length} inline fields`);
Parameters:
state
any
required

getStructuredContentTablesById

Find all tables inside a structured content block by ID Example:
const tables = editor.helpers.structuredContentCommands.getStructuredContentTablesById(
  "block-123",
  editor.state
);
console.log(`Block contains ${tables.length} table(s)`);
Parameters:
id
string
required
Structured content block ID
state
any
required

getStructuredContentByGroup

Find all structured content nodes that share the same group identifier. Example:
const fields = editor.helpers.structuredContentCommands.getStructuredContentByGroup('pricing', editor.state);
fields.forEach(({ node, pos }) => {
  console.log(node.attrs.tag, pos);
});
Parameters:
groupOrGroups
string | Array<string>
required
Group identifier or array of group identifiers
state
any
required

getStructuredContentTags

Get all structured content tags (inline and block) in the document Example:
const allTags = editor.helpers.structuredContentCommands.getStructuredContentTags(editor.state);
console.log(`Found ${allTags.length} structured content elements`);
Parameters:
state
any
required

getStructuredContentTagsById

Get structured content tag(s) by ID Example:
const field = editor.helpers.structuredContentCommands.getStructuredContentTagsById(
  "field-123",
  editor.state
);
if (field.length) console.log("Found field:", field[0].node.attrs);
Parameters:
idOrIds
string | Array<string>
required
Single ID or array of IDs to find
state
any
required

Types

StructuredContentLockMode

type StructuredContentLockMode = 'unlocked' | 'sdtLocked' | 'contentLocked' | 'sdtContentLocked'

StructuredContentInlineInsert

StructuredContentBlockInsert

StructuredContentUpdate

StructuredContentTableAppendRowsOptions

Source code