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

# StructuredContent extension

export const SourceCodeLink = ({extension, path}) => {
  const githubPath = path || `packages/super-editor/src/editors/v1/extensions/${extension.toLowerCase()}`;
  const githubUrl = `https://github.com/superdoc-dev/superdoc/tree/main/${githubPath}`;
  return <div>
      <p>
        <a href={githubUrl} target="_blank" rel="noopener noreferrer">
          View on GitHub →
        </a>
      </p>
    </div>;
};

export const SuperDocEditor = ({html = '<p>Start editing...</p>', height = '400px', maxHeight = '400px', onReady = null, showExport = true, customButtons = null}) => {
  const [ready, setReady] = useState(false);
  const editorRef = useRef(null);
  const containerIdRef = useRef(`editor-${Math.random().toString(36).substr(2, 9)}`);
  const DEV_DIST_URL = 'http://localhost:9094/dist';
  const UNPKG_DIST_URL = 'https://unpkg.com/superdoc@latest/dist';
  const getBaseUrl = async () => {
    const isDev = typeof window !== 'undefined' && window.location.hostname === 'localhost';
    if (isDev) {
      try {
        const res = await fetch(`${DEV_DIST_URL}/superdoc.min.js`, {
          method: 'HEAD'
        });
        if (res.ok) {
          console.info('[SuperDoc Docs] Using local build from', DEV_DIST_URL);
          return DEV_DIST_URL;
        }
        console.warn('[SuperDoc Docs] Local dev server returned', res.status, '- falling back to unpkg');
      } catch (err) {
        console.warn('[SuperDoc Docs] Local dev server not reachable: falling back to unpkg.', 'Run `pnpm dev:docs` from the repo root to use your local build.', err.message);
      }
    }
    return UNPKG_DIST_URL;
  };
  const ensureStyle = baseUrl => {
    const styleHref = `${baseUrl}/style.css`;
    if (document.querySelector(`link[href="${styleHref}"]`)) return;
    const link = document.createElement('link');
    link.rel = 'stylesheet';
    link.href = styleHref;
    document.head.appendChild(link);
  };
  const loadSuperDoc = baseUrl => {
    if (window.SuperDoc) return Promise.resolve();
    const scriptSrc = `${baseUrl}/superdoc.min.js`;
    const existingScript = document.querySelector(`script[src="${scriptSrc}"]`);
    if (existingScript) {
      if (window.SuperDoc) return Promise.resolve();
      return new Promise((resolve, reject) => {
        existingScript.addEventListener('load', resolve, {
          once: true
        });
        existingScript.addEventListener('error', reject, {
          once: true
        });
      });
    }
    return new Promise((resolve, reject) => {
      const script = document.createElement('script');
      script.src = scriptSrc;
      script.onload = resolve;
      script.onerror = reject;
      document.body.appendChild(script);
    });
  };
  const initEditor = () => {
    setTimeout(() => {
      if (!window.SuperDoc) return;
      if (!document.getElementById(containerIdRef.current)) return;
      if (editorRef.current) return;
      editorRef.current = new window.SuperDoc({
        selector: `#${containerIdRef.current}`,
        html,
        rulers: true,
        contained: true,
        onReady: () => {
          setReady(true);
          if (onReady) onReady(editorRef.current);
        }
      });
    }, 100);
  };
  useEffect(() => {
    let cancelled = false;
    const boot = async () => {
      try {
        const baseUrl = await getBaseUrl();
        ensureStyle(baseUrl);
        await loadSuperDoc(baseUrl);
        if (!cancelled) initEditor();
      } catch (error) {
        console.error('Failed to boot SuperDoc:', error);
      }
    };
    boot();
    return () => {
      cancelled = true;
      editorRef.current?.destroy?.();
      editorRef.current = null;
    };
  }, []);
  const exportDocx = () => {
    if (editorRef.current?.export) {
      editorRef.current.export();
    }
  };
  return <div className="border rounded-lg bg-white overflow-hidden">
      {ready && (showExport || customButtons) && <div className="px-3 py-2 bg-gray-50 border-b">
          {customButtons && <div className="space-y-1 mb-2">
              {customButtons.map((row, rowIndex) => <div key={rowIndex} className="flex gap-1">
                  {row.map((btn, i) => <button key={i} onClick={() => btn.onClick(editorRef.current)} className={btn.className || 'flex-1 px-2 py-1 bg-gray-100 text-gray-700 text-xs rounded hover:bg-gray-200'}>
                      {btn.label}
                    </button>)}
                </div>)}
            </div>}
          {showExport && <div className="text-right">
              <button onClick={exportDocx} className="px-3 py-1 bg-blue-500 text-white text-xs rounded hover:bg-blue-600">
                Export DOCX
              </button>
            </div>}
        </div>}
      <div id={containerIdRef.current} style={{
    height,
    maxHeight,
    paddingLeft: '5px'
  }} />
      <style jsx>{`
        #${containerIdRef.current} .superdoc__layers {
          max-width: 660px !important;
        }
        #${containerIdRef.current} .super-editor {
          max-width: 100% !important;
          width: 100% !important;
          color: #000;
        }
        #${containerIdRef.current} .editor-element {
          width: 100% !important;
          min-width: unset !important;
          transform: none !important;
        }
        #${containerIdRef.current} .editor-element {
          h1,
          h2,
          h3,
          h4,
          h5,
          strong {
            color: #000;
          }
        }
      `}</style>
    </div>;
};

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`)

<SuperDocEditor
  html={`<p><b>Service Agreement</b></p><p>This agreement is entered into by and between <i>Acme Corp</i> ("Company") and the client identified below.</p><p>Client name: ________</p><p>The Company agrees to provide consulting services under the following terms:</p><p>________</p>`}
  height="350px"
  onReady={(superdoc) => {
const editor = superdoc?.activeEditor || superdoc?.editor
if (!editor?.commands) return

// Find "________" in "Client name:" paragraph and replace with inline field
let inlinePos = null
editor.state.doc.descendants((node, pos) => {
  if (node.isText && node.text.includes('________') && inlinePos === null) {
    inlinePos = pos + node.text.indexOf('________')
  }
})
if (inlinePos !== null) {
  editor.commands.setTextSelection({ from: inlinePos, to: inlinePos + 8 })
  editor.commands.insertStructuredContentInline({
    attrs: { id: '1', alias: 'Client Name' },
    text: 'John Doe',
  })
}

// Find the second "________" paragraph and replace with block field
let blockPos = null
editor.state.doc.descendants((node, pos) => {
  if (node.isText && node.text.includes('________')) {
    blockPos = pos + node.text.indexOf('________')
  }
})
if (blockPos !== null) {
  editor.commands.setTextSelection({ from: blockPos, to: blockPos + 8 })
  editor.commands.insertStructuredContentBlock({
    attrs: { id: '2', alias: 'Payment Terms' },
    json: { type: 'paragraph', content: [{ type: 'text', text: 'Payment is due within 30 days of invoice date. Late payments incur a 1.5% monthly fee.' }] },
  })
}
}}
  customButtons={[
[
  {
    label: 'Update client name',
    onClick: (superdoc) => {
      const editor = superdoc?.activeEditor || superdoc?.editor
      if (!editor?.commands) return
      editor.commands.updateStructuredContentById('1', { text: 'Jane Smith' });
    }
  },
  {
    label: 'Update payment terms',
    onClick: (superdoc) => {
      const editor = superdoc?.activeEditor || superdoc?.editor
      if (!editor?.commands) return
      editor.commands.updateStructuredContentById('2', {
        json: { type: 'paragraph', content: [{ type: 'text', text: 'Net-15 payment terms apply. A 2% early payment discount is available for invoices settled within 7 days.' }] }
      });
    }
  },
],
[
  {
    label: 'Delete all fields',
    onClick: (superdoc) => {
      const editor = superdoc?.activeEditor || superdoc?.editor
      if (!editor?.commands) return
      const fields = editor.helpers.structuredContentCommands.getStructuredContentTags(editor.state);
      editor.commands.deleteStructuredContent(fields);
    }
  },
]
]}
/>

## Quick start

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

<ParamField path="structuredContentClass" type="string" default="sd-structured-content-block-tag">
  CSS class for the block
</ParamField>

<ParamField path="htmlAttributes" type="Object">
  HTML attributes for structured content blocks
</ParamField>

## Attributes

Node attributes that can be set and retrieved:

<ParamField path="id" type="string">
  Unique identifier for the structured content block

  <Info>
    The `id` attribute must be a **numeric string** for valid DOCX output (per
    ECMA-376
    [§17.5.2.18](https://learn.microsoft.com/en-us/openspecs/office_standards/ms-oe376/9bf45b56-eb07-4978-af7a-57548641667d)).
    Use `Date.now().toString()` or sequential integers instead of UUIDs.
  </Info>
</ParamField>

<ParamField path="tag" type="string">
  Content control tag (e.g., 'block\_table\_sdt')
</ParamField>

<ParamField path="alias" type="string" default="Structured content">
  Display name for the block
</ParamField>

<ParamField path="lockMode" type="StructuredContentLockMode" default="unlocked">
  Controls editing and deletion restrictions on the structured content node. See [Lock modes](#lock-modes) below.
</ParamField>

## Lock modes

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.

| Lock mode          | Wrapper   | Content   | Use case                                          |
| ------------------ | --------- | --------- | ------------------------------------------------- |
| `unlocked`         | Deletable | Editable  | Default — no restrictions                         |
| `sdtLocked`        | Protected | Editable  | Protect field structure, allow value changes      |
| `contentLocked`    | Deletable | Read-only | Display a computed value users can remove         |
| `sdtContentLocked` | Protected | Read-only | Fully protected field (e.g., system-generated ID) |

Set the lock mode when inserting:

<CodeGroup>
  ```javascript Usage theme={null}
  editor.commands.insertStructuredContentInline({
    attrs: {
      id: '3',
      alias: 'Account ID',
      lockMode: 'sdtContentLocked',
    },
    text: 'ACC-00042',
  });
  ```

  ```javascript Full Example theme={null}
  import { SuperDoc } from 'superdoc';
  import 'superdoc/style.css';

  const superdoc = new SuperDoc({
    selector: '#editor',
    document: yourFile,
    onReady: (superdoc) => {
      const editor = superdoc.activeEditor;
      editor.commands.insertStructuredContentInline({
        attrs: {
          id: '3',
          alias: 'Account ID',
          lockMode: 'sdtContentLocked',
        },
        text: 'ACC-00042',
      });
    },
  });
  ```
</CodeGroup>

Change the lock mode on an existing field:

<CodeGroup>
  ```javascript Usage theme={null}
  editor.commands.updateStructuredContentById('1', {
    attrs: { lockMode: 'contentLocked' },
  });
  ```

  ```javascript Full Example theme={null}
  import { SuperDoc } from 'superdoc';
  import 'superdoc/style.css';

  const superdoc = new SuperDoc({
    selector: '#editor',
    document: yourFile,
    onReady: (superdoc) => {
      const editor = superdoc.activeEditor;
      editor.commands.updateStructuredContentById('1', {
        attrs: { lockMode: 'contentLocked' },
      });
    },
  });
  ```
</CodeGroup>

<Expandable title="How lock enforcement works">
  Lock modes are enforced at the editor plugin level using a three-layer defense:

  1. **Key interception** — Delete, Backspace, and Cut are blocked before a transaction is created, preventing cursor jumps
  2. **Text input blocking** — Typing is silently blocked in content-locked nodes
  3. **Transaction filter** — Safety net that catches paste, drag-drop, and programmatic edits

  Users can still place their cursor inside locked content and select text for copying. Only modifications are blocked.
</Expandable>

<Info>
  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.
</Info>

## Commands

### `insertStructuredContentInline`

Inserts a structured content inline at the current selection.

**Example:**

<CodeGroup>
  ```javascript Usage theme={null}
  editor.commands.insertStructuredContentInline({
    attrs: {
      id: '1',
      alias: 'Customer Name',
      lockMode: 'sdtLocked', // optional, defaults to 'unlocked'
    },
    text: 'John Doe',
  });
  ```

  ```javascript Full Example theme={null}
  import { SuperDoc } from 'superdoc';
  import 'superdoc/style.css';

  const superdoc = new SuperDoc({
    selector: '#editor',
    document: yourFile,
    onReady: (superdoc) => {
      const editor = superdoc.activeEditor;
      editor.commands.insertStructuredContentInline({
        attrs: {
          id: '1',
          alias: 'Customer Name',
          lockMode: 'sdtLocked',
        },
        text: 'John Doe',
      });
    },
  });
  ```
</CodeGroup>

**Parameters:**

<ParamField path="options" type="StructuredContentInlineInsert" required />

### `insertStructuredContentBlock`

Inserts a structured content block at the current selection.

**Example:**

<CodeGroup>
  ```javascript Usage theme={null}
  editor.commands.insertStructuredContentBlock({
    attrs: {
      id: '2',
      alias: 'Terms Section',
      lockMode: 'sdtContentLocked', // optional, defaults to 'unlocked'
    },
    html: '<p>These terms are non-negotiable.</p>',
  });
  ```

  ```javascript Full Example theme={null}
  import { SuperDoc } from 'superdoc';
  import 'superdoc/style.css';

  const superdoc = new SuperDoc({
    selector: '#editor',
    document: yourFile,
    onReady: (superdoc) => {
      const editor = superdoc.activeEditor;
      editor.commands.insertStructuredContentBlock({
        attrs: {
          id: '2',
          alias: 'Terms Section',
          lockMode: 'sdtContentLocked',
        },
        html: '<p>These terms are non-negotiable.</p>',
      });
    },
  });
  ```
</CodeGroup>

**Parameters:**

<ParamField path="options" type="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:**

<CodeGroup>
  ```javascript Usage theme={null}
  // 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' },
  });
  ```

  ```javascript Full Example theme={null}
  import { SuperDoc } from 'superdoc';
  import 'superdoc/style.css';

  const superdoc = new SuperDoc({
    selector: '#editor',
    document: yourFile,
    onReady: (superdoc) => {
      const editor = superdoc.activeEditor;

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

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

**Parameters:**

<ParamField path="id" type="string" required>
  Unique identifier of the field
</ParamField>

<ParamField path="options" type="StructuredContentUpdate" required />

### `deleteStructuredContent`

Removes a structured content.

**Parameters:**

<ParamField path="structuredContentTags" type="Array<any>" required />

### `deleteStructuredContentById`

Removes a structured content by ID.

**Parameters:**

<ParamField path="idOrIds" type="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:**

<CodeGroup>
  ```javascript Usage theme={null}
  editor.commands.updateStructuredContentByGroup('pricing', {
    text: '$99.00'
  })
  ```

  ```javascript Full Example theme={null}
  import { SuperDoc } from 'superdoc';
  import 'superdoc/style.css';

  const superdoc = new SuperDoc({
    selector: '#editor',
    document: yourFile,
    onReady: (superdoc) => {
      const editor = superdoc.activeEditor;
      editor.commands.updateStructuredContentByGroup('pricing', {
        text: '$99.00'
      })
    },
  });
  ```
</CodeGroup>

**Parameters:**

<ParamField path="group" type="string" required>
  Group identifier to match
</ParamField>

<ParamField path="options" type="StructuredContentUpdate">
  Update options (same as `updateStructuredContentById`)
</ParamField>

### `deleteStructuredContentByGroup`

Remove all structured content fields that share the same group identifier.

**Example:**

<CodeGroup>
  ```javascript Usage theme={null}
  editor.commands.deleteStructuredContentByGroup('pricing')
  editor.commands.deleteStructuredContentByGroup(['pricing', 'deprecated'])
  ```

  ```javascript Full Example theme={null}
  import { SuperDoc } from 'superdoc';
  import 'superdoc/style.css';

  const superdoc = new SuperDoc({
    selector: '#editor',
    document: yourFile,
    onReady: (superdoc) => {
      const editor = superdoc.activeEditor;
      editor.commands.deleteStructuredContentByGroup('pricing')
      editor.commands.deleteStructuredContentByGroup(['pricing', 'deprecated'])
    },
  });
  ```
</CodeGroup>

**Parameters:**

<ParamField path="groupOrGroups" type="string | Array<string>" required>
  Group identifier or array of group identifiers
</ParamField>

### `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:**

<CodeGroup>
  ```javascript Usage theme={null}
  editor.commands.appendRowsToStructuredContentTable({
    id: "block-123",
    tableIndex: 0,
    rows: [
      ["A", "B"],
      ["C", "D"],
    ],
    copyRowStyle: true,
  });
  ```

  ```javascript Full Example theme={null}
  import { SuperDoc } from 'superdoc';
  import 'superdoc/style.css';

  const superdoc = new SuperDoc({
    selector: '#editor',
    document: yourFile,
    onReady: (superdoc) => {
      const editor = superdoc.activeEditor;
      editor.commands.appendRowsToStructuredContentTable({
        id: "block-123",
        tableIndex: 0,
        rows: [
          ["A", "B"],
          ["C", "D"],
        ],
        copyRowStyle: true,
      });
    },
  });
  ```
</CodeGroup>

**Parameters:**

<ParamField path="options" type="StructuredContentTableAppendRowsOptions" required>
  Append configuration
</ParamField>

## Helpers

### `getStructuredContentBlockTags`

Get all block-level structured content tags in the document

**Example:**

<CodeGroup>
  ```javascript Usage theme={null}
  const blocks = editor.helpers.structuredContentCommands.getStructuredContentBlockTags(editor.state);
  console.log(`Found ${blocks.length} structured content blocks`);
  ```

  ```javascript Full Example theme={null}
  import { SuperDoc } from 'superdoc';
  import 'superdoc/style.css';

  const superdoc = new SuperDoc({
    selector: '#editor',
    document: yourFile,
    onReady: (superdoc) => {
      const editor = superdoc.activeEditor;
      const blocks = editor.helpers.structuredContentCommands.getStructuredContentBlockTags(editor.state);
      console.log(`Found ${blocks.length} structured content blocks`);
    },
  });
  ```
</CodeGroup>

**Parameters:**

<ParamField path="state" type="any" required />

### `getStructuredContentInlineTags`

Get all inline structured content tags in the document

**Example:**

<CodeGroup>
  ```javascript Usage theme={null}
  const inlines = editor.helpers.structuredContentCommands.getStructuredContentInlineTags(editor.state);
  console.log(`Found ${inlines.length} inline fields`);
  ```

  ```javascript Full Example theme={null}
  import { SuperDoc } from 'superdoc';
  import 'superdoc/style.css';

  const superdoc = new SuperDoc({
    selector: '#editor',
    document: yourFile,
    onReady: (superdoc) => {
      const editor = superdoc.activeEditor;
      const inlines = editor.helpers.structuredContentCommands.getStructuredContentInlineTags(editor.state);
      console.log(`Found ${inlines.length} inline fields`);
    },
  });
  ```
</CodeGroup>

**Parameters:**

<ParamField path="state" type="any" required />

### `getStructuredContentTablesById`

Find all tables inside a structured content block by ID

**Example:**

<CodeGroup>
  ```javascript Usage theme={null}
  const tables = editor.helpers.structuredContentCommands.getStructuredContentTablesById(
    "block-123",
    editor.state
  );
  console.log(`Block contains ${tables.length} table(s)`);
  ```

  ```javascript Full Example theme={null}
  import { SuperDoc } from 'superdoc';
  import 'superdoc/style.css';

  const superdoc = new SuperDoc({
    selector: '#editor',
    document: yourFile,
    onReady: (superdoc) => {
      const editor = superdoc.activeEditor;
      const tables = editor.helpers.structuredContentCommands.getStructuredContentTablesById(
        "block-123",
        editor.state
      );
      console.log(`Block contains ${tables.length} table(s)`);
    },
  });
  ```
</CodeGroup>

**Parameters:**

<ParamField path="id" type="string" required>
  Structured content block ID
</ParamField>

<ParamField path="state" type="any" required />

### `getStructuredContentByGroup`

Find all structured content nodes that share the same group identifier.

**Example:**

<CodeGroup>
  ```javascript Usage theme={null}
  const fields = editor.helpers.structuredContentCommands.getStructuredContentByGroup('pricing', editor.state);
  fields.forEach(({ node, pos }) => {
    console.log(node.attrs.tag, pos);
  });
  ```

  ```javascript Full Example theme={null}
  import { SuperDoc } from 'superdoc';
  import 'superdoc/style.css';

  const superdoc = new SuperDoc({
    selector: '#editor',
    document: yourFile,
    onReady: (superdoc) => {
      const editor = superdoc.activeEditor;
      const fields = editor.helpers.structuredContentCommands.getStructuredContentByGroup('pricing', editor.state);
      fields.forEach(({ node, pos }) => {
        console.log(node.attrs.tag, pos);
      });
    },
  });
  ```
</CodeGroup>

**Parameters:**

<ParamField path="groupOrGroups" type="string | Array<string>" required>
  Group identifier or array of group identifiers
</ParamField>

<ParamField path="state" type="any" required />

### `getStructuredContentTags`

Get all structured content tags (inline and block) in the document

**Example:**

<CodeGroup>
  ```javascript Usage theme={null}
  const allTags = editor.helpers.structuredContentCommands.getStructuredContentTags(editor.state);
  console.log(`Found ${allTags.length} structured content elements`);
  ```

  ```javascript Full Example theme={null}
  import { SuperDoc } from 'superdoc';
  import 'superdoc/style.css';

  const superdoc = new SuperDoc({
    selector: '#editor',
    document: yourFile,
    onReady: (superdoc) => {
      const editor = superdoc.activeEditor;
      const allTags = editor.helpers.structuredContentCommands.getStructuredContentTags(editor.state);
      console.log(`Found ${allTags.length} structured content elements`);
    },
  });
  ```
</CodeGroup>

**Parameters:**

<ParamField path="state" type="any" required />

### `getStructuredContentTagsById`

Get structured content tag(s) by ID

**Example:**

<CodeGroup>
  ```javascript Usage theme={null}
  const field = editor.helpers.structuredContentCommands.getStructuredContentTagsById(
    "field-123",
    editor.state
  );
  if (field.length) console.log("Found field:", field[0].node.attrs);
  ```

  ```javascript Full Example theme={null}
  import { SuperDoc } from 'superdoc';
  import 'superdoc/style.css';

  const superdoc = new SuperDoc({
    selector: '#editor',
    document: yourFile,
    onReady: (superdoc) => {
      const editor = superdoc.activeEditor;
      const field = editor.helpers.structuredContentCommands.getStructuredContentTagsById(
        "field-123",
        editor.state
      );
      if (field.length) console.log("Found field:", field[0].node.attrs);
    },
  });
  ```
</CodeGroup>

**Parameters:**

<ParamField path="idOrIds" type="string | Array<string>" required>
  Single ID or array of IDs to find
</ParamField>

<ParamField path="state" type="any" required />

## Types

### `StructuredContentLockMode`

```typescript theme={null}
type StructuredContentLockMode = 'unlocked' | 'sdtLocked' | 'contentLocked' | 'sdtContentLocked'
```

### `StructuredContentInlineInsert`

<Expandable title="Properties">
  <ResponseField name="text" type="string">
    Text content to insert
  </ResponseField>

  <ResponseField name="json" type="Object">
    ProseMirror JSON
  </ResponseField>

  <ResponseField name="attrs" type="Object">
    Node attributes (`id`, `alias`, `tag`, `lockMode`, `group`)
  </ResponseField>
</Expandable>

### `StructuredContentBlockInsert`

<Expandable title="Properties">
  <ResponseField name="html" type="string">
    HTML content to insert
  </ResponseField>

  <ResponseField name="json" type="Object">
    ProseMirror JSON
  </ResponseField>

  <ResponseField name="attrs" type="Object">
    Node attributes (`id`, `alias`, `tag`, `lockMode`, `group`)
  </ResponseField>
</Expandable>

### `StructuredContentUpdate`

<Expandable title="Properties">
  <ResponseField name="text" type="string">
    Replace content with text (only for structured content inline)
  </ResponseField>

  <ResponseField name="html" type="string">
    Replace content with HTML (only for structured content block)
  </ResponseField>

  <ResponseField name="json" type="Object">
    Replace content with ProseMirror JSON (overrides html)
  </ResponseField>

  <ResponseField name="attrs" type="Object">
    Update attributes only (preserves content). Supports `lockMode`, `alias`, `tag`.
  </ResponseField>
</Expandable>

### `StructuredContentTableAppendRowsOptions`

<Expandable title="Properties">
  <ResponseField name="id" type="string" required>
    Structured content block identifier
  </ResponseField>

  <ResponseField name="tableIndex" type="number">
    Index of the table inside the block
  </ResponseField>

  <ResponseField name="rows" type="Array<Array<string>> | Array<string>" required>
    Cell values to append
  </ResponseField>

  <ResponseField name="copyRowStyle" type="boolean">
    Clone the last row's styling when true
  </ResponseField>
</Expandable>

## Source code

<SourceCodeLink path="packages/super-editor/src/editors/v1/extensions/structured-content/structured-content.js" />
