@@ -46,11 +46,138 @@ Node attributes that can be set and retrieved:
4646 Display name for the block
4747</ParamField >
4848
49+ <ParamField path = " lockMode" type = " StructuredContentLockMode" default = " unlocked" >
50+ Controls editing and deletion restrictions on the structured content node. See [ Lock modes] ( #lock-modes ) below.
51+ </ParamField >
52+
53+ ## Lock modes
54+
55+ Structured content nodes support four lock modes based on the OOXML [ ` w:lock ` element] ( https://learn.microsoft.com/en-us/dotnet/api/documentformat.openxml.wordprocessing.lock ) (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.
56+
57+ | Lock mode | Wrapper | Content | Use case |
58+ | -----------| ---------| ---------| ----------|
59+ | ` unlocked ` | Deletable | Editable | Default — no restrictions |
60+ | ` sdtLocked ` | Protected | Editable | Protect field structure, allow value changes |
61+ | ` contentLocked ` | Deletable | Read-only | Display a computed value users can remove |
62+ | ` sdtContentLocked ` | Protected | Read-only | Fully protected field (e.g., system-generated ID) |
63+
64+ Set the lock mode when inserting:
65+
66+ <CodeGroup >
67+ ``` javascript Usage
68+ editor .commands .insertStructuredContentInline ({
69+ attrs: {
70+ id: ' 1' ,
71+ alias: ' Customer Name' ,
72+ lockMode: ' sdtLocked' ,
73+ },
74+ text: ' John Doe' ,
75+ });
76+ ```
77+
78+ ``` javascript Full Example
79+ import { SuperDoc } from ' superdoc' ;
80+ import ' superdoc/style.css' ;
81+
82+ const superdoc = new SuperDoc ({
83+ selector: ' #editor' ,
84+ document : yourFile,
85+ onReady : (superdoc ) => {
86+ const editor = superdoc .activeEditor ;
87+ editor .commands .insertStructuredContentInline ({
88+ attrs: {
89+ id: ' 1' ,
90+ alias: ' Customer Name' ,
91+ lockMode: ' sdtLocked' ,
92+ },
93+ text: ' John Doe' ,
94+ });
95+ },
96+ });
97+ ```
98+ </CodeGroup >
99+
100+ Change the lock mode on an existing field:
101+
102+ <CodeGroup >
103+ ``` javascript Usage
104+ editor .commands .updateStructuredContentById (' 1' , {
105+ attrs: { lockMode: ' contentLocked' },
106+ });
107+ ```
108+
109+ ``` javascript Full Example
110+ import { SuperDoc } from ' superdoc' ;
111+ import ' superdoc/style.css' ;
112+
113+ const superdoc = new SuperDoc ({
114+ selector: ' #editor' ,
115+ document : yourFile,
116+ onReady : (superdoc ) => {
117+ const editor = superdoc .activeEditor ;
118+ editor .commands .updateStructuredContentById (' 1' , {
119+ attrs: { lockMode: ' contentLocked' },
120+ });
121+ },
122+ });
123+ ```
124+ </CodeGroup >
125+
126+ Lock modes are enforced at the editor plugin level using a three-layer defense:
127+
128+ 1 . ** Key interception** — Delete, Backspace, and Cut are blocked before a transaction is created, preventing cursor jumps
129+ 2 . ** Text input blocking** — Typing is silently blocked in content-locked nodes
130+ 3 . ** Transaction filter** — Safety net that catches paste, drag-drop, and programmatic edits
131+
132+ Users can still place their cursor inside locked content and select text for copying. Only modifications are blocked.
133+
134+ <Info >
135+ Lock modes round-trip through DOCX. A document with ` w:lock ` elements in
136+ its SDT properties will import with the correct lock mode and export the
137+ ` w:lock ` element back to the saved file.
138+ </Info >
139+
49140## Commands
50141
51142### ` insertStructuredContentInline `
52143
53- Inserts a structured content inline at selection.
144+ Inserts a structured content inline at the current selection.
145+
146+ ** Example:**
147+
148+ <CodeGroup >
149+ ``` javascript Usage
150+ editor .commands .insertStructuredContentInline ({
151+ attrs: {
152+ id: ' 1' ,
153+ alias: ' Customer Name' ,
154+ lockMode: ' sdtLocked' , // optional, defaults to 'unlocked'
155+ },
156+ text: ' John Doe' ,
157+ });
158+ ```
159+
160+ ``` javascript Full Example
161+ import { SuperDoc } from ' superdoc' ;
162+ import ' superdoc/style.css' ;
163+
164+ const superdoc = new SuperDoc ({
165+ selector: ' #editor' ,
166+ document : yourFile,
167+ onReady : (superdoc ) => {
168+ const editor = superdoc .activeEditor ;
169+ editor .commands .insertStructuredContentInline ({
170+ attrs: {
171+ id: ' 1' ,
172+ alias: ' Customer Name' ,
173+ lockMode: ' sdtLocked' ,
174+ },
175+ text: ' John Doe' ,
176+ });
177+ },
178+ });
179+ ```
180+ </CodeGroup >
54181
55182** Parameters:**
56183
@@ -62,7 +189,43 @@ Inserts a structured content inline at selection.
62189
63190### ` insertStructuredContentBlock `
64191
65- Inserts a structured content block at selection.
192+ Inserts a structured content block at the current selection.
193+
194+ ** Example:**
195+
196+ <CodeGroup >
197+ ``` javascript Usage
198+ editor .commands .insertStructuredContentBlock ({
199+ attrs: {
200+ id: ' 2' ,
201+ alias: ' Terms Section' ,
202+ lockMode: ' sdtContentLocked' , // optional, defaults to 'unlocked'
203+ },
204+ html: ' <p>These terms are non-negotiable.</p>' ,
205+ });
206+ ```
207+
208+ ``` javascript Full Example
209+ import { SuperDoc } from ' superdoc' ;
210+ import ' superdoc/style.css' ;
211+
212+ const superdoc = new SuperDoc ({
213+ selector: ' #editor' ,
214+ document : yourFile,
215+ onReady : (superdoc ) => {
216+ const editor = superdoc .activeEditor ;
217+ editor .commands .insertStructuredContentBlock ({
218+ attrs: {
219+ id: ' 2' ,
220+ alias: ' Terms Section' ,
221+ lockMode: ' sdtContentLocked' ,
222+ },
223+ html: ' <p>These terms are non-negotiable.</p>' ,
224+ });
225+ },
226+ });
227+ ```
228+ </CodeGroup >
66229
67230** Parameters:**
68231
@@ -78,6 +241,53 @@ Updates a single structured content field by its unique ID.
78241IDs are unique identifiers, so this will update at most one field.
79242If the updated node does not match the schema, it will not be updated.
80243
244+ Pass ` attrs ` alone to change attributes (like ` lockMode ` ) without replacing content:
245+
246+ ** Example:**
247+
248+ <CodeGroup >
249+ ``` javascript Usage
250+ // Update content
251+ editor .commands .updateStructuredContentById (' 1' , {
252+ text: ' Jane Smith' ,
253+ });
254+
255+ // Update lock mode only (preserves content)
256+ editor .commands .updateStructuredContentById (' 1' , {
257+ attrs: { lockMode: ' contentLocked' },
258+ });
259+
260+ // Update both content and attributes
261+ editor .commands .updateStructuredContentById (' 1' , {
262+ text: ' New value' ,
263+ attrs: { alias: ' Updated Label' , lockMode: ' sdtLocked' },
264+ });
265+ ```
266+
267+ ``` javascript Full Example
268+ import { SuperDoc } from ' superdoc' ;
269+ import ' superdoc/style.css' ;
270+
271+ const superdoc = new SuperDoc ({
272+ selector: ' #editor' ,
273+ document : yourFile,
274+ onReady : (superdoc ) => {
275+ const editor = superdoc .activeEditor ;
276+
277+ // Update content
278+ editor .commands .updateStructuredContentById (' 1' , {
279+ text: ' Jane Smith' ,
280+ });
281+
282+ // Update lock mode only (preserves content)
283+ editor .commands .updateStructuredContentById (' 1' , {
284+ attrs: { lockMode: ' contentLocked' },
285+ });
286+ },
287+ });
288+ ```
289+ </CodeGroup >
290+
81291** Parameters:**
82292
83293<ParamField path = " id" type = " string" required >
@@ -456,6 +666,12 @@ const superdoc = new SuperDoc({
456666
457667## Types
458668
669+ ### ` StructuredContentLockMode `
670+
671+ ``` typescript
672+ type StructuredContentLockMode = ' unlocked' | ' sdtLocked' | ' contentLocked' | ' sdtContentLocked'
673+ ` ` `
674+
459675### ` StructuredContentInlineInsert `
460676
461677<Expandable title="Properties">
@@ -466,7 +682,7 @@ const superdoc = new SuperDoc({
466682 ProseMirror JSON
467683 </ResponseField>
468684 <ResponseField name="attrs" type="Object">
469- Node attributes
685+ Node attributes ( ` id ` , ` alias ` , ` tag ` , ` lockMode ` , ` group ` )
470686 </ResponseField>
471687</Expandable>
472688
@@ -480,7 +696,7 @@ const superdoc = new SuperDoc({
480696 ProseMirror JSON
481697 </ResponseField>
482698 <ResponseField name="attrs" type="Object">
483- Node attributes
699+ Node attributes ( ` id ` , ` alias ` , ` tag ` , ` lockMode ` )
484700 </ResponseField>
485701</Expandable>
486702
@@ -497,7 +713,7 @@ const superdoc = new SuperDoc({
497713 Replace content with ProseMirror JSON (overrides html)
498714 </ResponseField>
499715 <ResponseField name="attrs" type="Object">
500- Update attributes only (preserves content)
716+ Update attributes only (preserves content). Supports ` lockMode ` , ` alias ` , ` tag ` .
501717 </ResponseField>
502718</Expandable>
503719
0 commit comments