Skip to content

API reference / Common / Engine types / TextBlock

Type Alias: TextBlock ​

ts
type TextBlock = 
  | {
  paragraph: TextParagraph;
}
  | {
  table: TextTable;
}
  | {
  control: TextControlBlock;
}
  | {
  customXml: TextCustomXmlBlock;
};

One block in a TextStory.

A paragraph is the common case — and the only block a DrawingML a:txBody (or an xlsx cell) ever holds (DrawingML tables are a graphicFrame in the shape tree, not story content). The other three appear only in the docx main flow, honored by the wordprocessing host and ignored by the rest (the superset-union rule):

  • Table (w:tbl) is an embedding point for the table sub-domain — one atomic slot in this story, its content edited in an offset space of its own.
  • Control (w:sdt) is a native container of nested blocks: it wraps them with control metadata and contributes no characters of its own, its extent riding as a mark over the range its blocks realize — so its blocks stay in this story's offset space, with no boundary units around them. CustomXml (w:customXml) is its twin, carried the same way and differing only in what the wrapper declares.

Deliberately not a block, though it can span several: a field. A multi-paragraph result is a w:fldChar begin in one paragraph and an end in another, with the paragraphs between them left exactly where the file put them — there is no block-level field element in the schema, and a TOC is that shape. See Text Fields.

Nor are bookmarks: a bookmark is two one-unit spans in paragraphs (TextSpan::BookmarkStart … BookmarkEnd), and a marker the file writes between blocks moves into the nearest paragraph on import. Nor are comment ranges, permissions, proofing errors, and the move / custom-XML revision ranges, which mark positions rather than structure; and w:sectPr is a property. Nor are the revision containers (w:ins / w:del / w:moveFrom / w:moveTo) or math (m:oMathPara / m:oMath), though EG_RunLevelElts stands both where a block goes. Each has one type for both levels — unlike w:sdt and w:customXml, which have two and so are modelled at both — and one type has one content model, so the position cannot change what they hold. The in-paragraph spelling is the common one, so that is the one modelled: a block-level revision container is loose runs and import gives them a Paragraph, the revision riding the spans they become as span markup; a block-level equation gets a paragraph holding a TextSpan::Math. Each costs a paragraph mark the file had no element for, and buys one object per construct however the file spelled it — so accept and reject, and the math domain, need no second form. See Text Model.