In the Slides API, text can be contained in shapes or in table cells. Before you can manipulate and style text, you need to understand its structure and how styling works.
This page describes how text is represented in the Slides API.
Sequences of text elements
The text contained in a shape or a table cell is made up of a sequence of TextElement structures. This sequence represents the structure of text, in the order it appears from start to end.
For example, consider the contents of this slide—all contained in one text box:
The slide above has one text box, whose text
field contains a sequence
of text elements as shown in the following diagram:
More concretely, this sequence of text is represented in the Slides API as follows:
"textElements": [ {
"endIndex": 224,
"paragraphMarker": { "style": {} }
}, {
"endIndex": 130,
"textRun": { "content": "Li lingues differe in li grammatica e li vocabules. Omnicos directe al desirabilite de un nov ", "style": {} }
}, {
"endIndex": 143,
"startIndex": 130,
"textRun": { "content": "lingua franca", "style": { "italic": True } }
}, {
"endIndex": 224,
"startIndex": 143,
"textRun": { "content": ": solmen va esser necessi far:\n", "style": {} }
}, {
"endIndex": 243,
"startIndex": 224,
"paragraphMarker": {
"style": { "indentStart": { "magnitude": 36, "unit": "PT" }, "direction": "LEFT_TO_RIGHT", "indentFirstLine": { "magnitude": 18, "unit": "PT" }, "spacingMode": "COLLAPSE_LISTS" },
"bullet": { "listId": "foo123", "glyph": "\u25cf" }
}
}, {
"endIndex": 243,
"startIndex": 224,
"textRun": { "content": "uniform grammatica\n", "style": {} }
}, {
"endIndex": 257,
"startIndex": 243,
"paragraphMarker": {
"style": { "indentStart": { "magnitude": 36, "unit": "PT" }, "direction": "LEFT_TO_RIGHT", "indentFirstLine": { "magnitude": 18, "unit": "PT" }, "spacingMode": "COLLAPSE_LISTS" },
"bullet": { "listId": "foo123", "glyph": "\u25cf" }
}
}, {
"endIndex": 257,
"startIndex": 243,
"textRun": { "content": "Pronunciation\n", "style": {} }
}, {
"endIndex": 277,
"startIndex": 257,
"paragraphMarker": {
"style": { "indentStart": { "magnitude": 36, "unit": "PT" }, "indentFirstLine": { "magnitude": 18, "unit": "PT" }, "spacingMode": "COLLAPSE_LISTS" },
"bullet": { "listId": "foo123", "glyph": "\u25cf" }
}
}, {
"endIndex": 277,
"startIndex": 257,
"textRun": { "content": "plu sommun paroles.\n", "style": {} }
}, {
"endIndex": 500,
"startIndex": 277,
"paragraphMarker": { "style": {} }
}, {
"endIndex": 500,
"startIndex": 277,
"textRun": { "content": "Ka swu thefognay, tay waddeant varpa u inzo.\n", "style": {} }
}]
TextElement contents
Each text element contains a zero-based start index and end index, which describe the element's location within the full text of the page element, together with one of the following types of text object:
Text kind | Description |
---|---|
ParagraphMarker | This text element represents the start of a new paragraph. The start and end index of the text element represents the full span of the paragraph, including the newline character that ends the paragraph. A paragraph never overlaps another paragraph. Paragraphs always end in a newline character, so there's always a newline at the end of the text contents of a shape or table cell. Paragraphs can belong to bulleted or numbered lists. If so, the ParagraphMarker.bullet field contents include a list ID. This ID references a list element that exists inside TextContent alongside the TextElement sequence. Paragraphs within the same logical list will refer to the same list ID. |
TextRun | This text element represents a contiguous string of text that all has the same text style. Text runs never cross paragraph boundaries: even if the text ending one paragraph has the same styling as the text starting the next paragraph, the contents are split after the newline character to form separate text runs. If you need to process the full text string inside a page element, iterate through all of the text elements, concatenating the strings found in all of the text runs. |
AutoText | Autotext refers to places in the text that change dynamically depending on the context. In Slides, this is used to represent the current slide number inside text. |
Modifying text contents
When you need to modify text using the Slides API, you don't have to explicitly
create all the appropriate text elements. Instead, you can operate on text like
you would in the Slides editor: by inserting text, deleting ranges, and
updating styles on ranges. These operations implicitly create ParagraphMarker
and TextRun
elements as needed to reflect your changes.
Inserting text
You can insert text at an index using the
InsertTextRequest
request in a call to
batchUpdate. This
method's insertionIndex
field specifies where to insert the text; you can
compute this index using the start and end index fields inside text elements.
Text insertion has some side effects that mirror the behavior of the Slides editor:
- Inserting a newline character implicitly creates a new paragraph,
creating a
ParagraphMarker
text element that starts at the newline's index and ends at the following newline. The paragraph style—including bullet and list details — is copied from the current paragraph to the new paragraph. - The style of inserted characters is determined automatically, generally
keeping the same text style that existed at the insertion index. As a result,
the text is generally inserted into the existing
TextRun
at that index. You can update this style later using an UpdateTextStyle request.
Deleting text
You can delete a range of text using the DeleteTextRequest message in a call to batchUpdate. Deleting text involves some subtleties:
- A deletion that crosses a paragraph boundary merges the two paragraphs,
deleting the separating
ParagraphMarker
text element. - The new merged paragraph will use a combined paragraph style, matching behavior in the Slides editor.
- A deletion whose range encompasses a text run removes all the content from a text run, and it also deletes the text run itself.
- A deletion whose range encompasses an
AutoText
element deletes theAutoText
element.
Updating text style
The rendered appearance of text in a slide is determined by text style properties:
- Paragraph styles like indention, alignment, and bullet glyphs, are defined by properties on paragraph markers.
- Character styles like bold, italic, and underline, are defined by properties on individual text runs.
Updating character style
You can update character styles using the UpdateTextStyleRequest message in a call to batchUpdate.
Like other text operations, the character style is applied to a range
of text and implicitly creates new TextRun
objects as needed.
Setting some character styles implicitly updates other related styles to match the behavior in the Slides editor. For example, adding a link automatically changes the text foreground color and underline properties. See the TextStyle reference documentation for more details.
Updating paragraph style
You can update paragraph styles using the UpdateParagraphStyleRequest message in a call to batchUpdate.
The Slides API supports a CreateParagraphBulletsRequest that mirrors the functionality of the bullet presets in the Slides editor for creation of bulleted and numbered lists. Similarly, DeleteParagraphBulletsRequest removes any existing bullets on paragraphs.
Inherited styles
Some shapes, known as placeholders, can inherit text styles from other, parent shapes: see placeholders to learn more about shape inheritance in general.
This section focuses on how style inheritance works to create the final, rendered text styles displayed in a slide.
Style representation in placeholders
The section on placeholders describes how inheritance works between parent and child shapes. Inheritance of text styles is handled by additional features within the inheritance model:
- Properties of ParagraphMaker text elements define paragraph formatting.
- Properties of TextRun text elements define character formatting.
- The content of parent placeholders contains eight such ParagraphMarker/TextRun pairs (to support eight levels of list nesting).
- A child placeholder inherits its default text properties from these text elements in its parent's text content.
The following diagram shows one way to visualize these relationships:
The first ParagraphMarker/TextRun in the parent shape determines most of the inherited text styling; the styling in the remaining seven pairs only affects paragraphs at progressively more-deeply nested bullet levels:
Parent text element pair | Child formatting that it controls |
---|---|
First ParagraphMarker First TextRun |
Text style of level 0 (outermost) list paragraphs and all non-list paragraphs. |
Second ParagraphMarker Second TextRun |
Text style of remaining (nested) list levels 1-7 |
Third ParagraphMarker Third TextRun |
|
Fourth ParagraphMarker Fourth TextRun |
|
Fifth ParagraphMarker Fifth TextRun |
|
Sixth ParagraphMarker Sixth TextRun |
|
Seventh ParagraphMarker Seventh TextRun |
|
Eighth ParagraphMarker Eighth TextRun |
To access these pairs of text elements, use their explicit index within the
textElements
field as shown in the snippet below, which shows setting the
default (inheritable) styling for level 0 and non-list paragraphs:
"text": {
"textElements": [ {
"startIndex": 0,
"endIndex": 1,
"paragraphMarker": {
"style": { "alignment": "START", ... },
"bullet": { "nestingLevel": 0, ... }
}
},{
"startIndex": 0,
"endIndex": 1,
"textRun": {
"content": "\n",
"style": { "foregroundColor": { "opaqueColor": { "themeColor": "DARK1" } }, }
}
},{
...
} ]
}
Note that the content
field of a parent shape's TextRun
always consists of
a single newline character.
Inherited styles can be overridden
A child shape can specify styling properties on the ParagraphMarker and TextRun elements in its content. These locally specified properties will override any inherited properties within their local scope. Elements that do not specify any style will use the corresponding style inherited from the parent.
Removing an explicit style property from a child shape, so that it is no longer set, will cause it to inherit from the parent.
Example
Given the inheritance shown in the diagram above, suppose the shape
ParentPlaceholder
has the following text content:
"text": {
"textElements": [
{ "startIndex": 0, "endIndex": 1,
"paragraphMarker": {
"style": {"alignment": "START", ...},
"bullet": {"nestingLevel": 0, ...}
}
},
{ "startIndex": 0, "endIndex": 1,
"textRun": {
"content": "\n",
"style": {"foregroundColor": {"opaqueColor": {"themeColor": "DARK1"} }, }
...
}
},
{ "startIndex": 1, "endIndex": 2,
"paragraphMarker": {
"style": {"alignment": "END", ...},
"bullet": {"nestingLevel": 1, ...}
}
},
{ "startIndex": 1, "endIndex": 2,
"textRun": {
"content": "\n",
"style": {"foregroundColor": {"opaqueColor": {"themeColor": "LIGHT1"} }, ...}
}
},
...
]
}
And suppose the shape ChildPlaceholder
has the following text content:
"text": {
"textElements": [
{ "startIndex": 0, "endIndex": 1,
"paragraphMarker": {
"style": {},
}
},
{ "startIndex": 0, "endIndex": 1,
"textRun": {
"content": "This is my first paragraph\n",
"style": {},
}
...
},
{ "startIndex": 1, "endIndex": 2,
"paragraphMarker": {
"style": {},
"bullet": {
"nestingLevel": 1,
"listId": "someListId",
"glyph": "●"
}
}
},
{ "startIndex": 1, "endIndex": 2,
"textRun": {
"content": "This paragraph is in a list\n",
"style": {},
...
}
}
]
}
This results in the outcomes described in the following paragraphs.
Style inheritance for a plain paragraph
The child shape's first paragraph, which includes the text "This is my first paragraph", is a plain paragraph (not in a list). No elements in its text content specify any style properties, so it inherits all its character and paragraph styles from its parent. This causes the following rendering:
- Text: "This is my first paragraph" is the text rendered. Text itself is never inherited.
- Alignment: The text is rendered with
START
alignment, inherited from the parent's firstParagraphMarker
. - Foreground color: The text is rendered with
DARK1
foreground color, inherited from the parent's firstTextRun
.
Style inheritance for a list paragraph
The next paragraph, which includes the text "This paragraph is in a list", is in
a bulleted list at nesting level 1, since its corresponding ParagraphMarker
has its bullet
field set to this level. As a result, it inherits text and
paragraph style from nesting level 1 in the parent. This results in the
following rendering:
- Text: "This paragraph is in a list" is the text rendered. Text itself is never inherited.
- Alignment: The text is rendered with "END" alignment, inherited from the
parent's second
ParagraphMarker
. - Foreground color: The text is rendered with
LIGHT1
text foreground color, inherited from the parent's secondTextRun
.
Interactions between updating and inheriting text and paragraph styles
Text styles that aren't set in a child shape will inherit values from its parent. Text styles that are set in the child will "override" the parent values in some local scope.
You can use an UpdateTextStyleRequest to unset a child shape's text style, so that it no longer has a local override and thus inherits its syltes from the parent shape. Additionally, updating the child's text style to match the value inherited from a parent implicitly unsets the style so that it uses the inherited value.
This does not affect the visual appearance of text immediately after an update, but it may matter if you later update a paragraph or text style in a parent placeholder. This inheritance behavior matches the behavior of the Slides editor, so you can experiment with the outcomes of style changes before working against the API.
Example
Consider the definitions in the previous example for
ChildPlaceholder
and ParentPlaceholder
.
Now suppose you submit this UpdateTextStyleRequest:
{ "updateTextStyle": {
"objectId": "ChildPlaceholder",
"style": {"foregroundColor": {"opaqueColor": {"themeColor": "DARK1"} }, },
"textRange": { "type": "ALL" },
"fields": "foregroundColor"
}
}
This request attempts to set a DARK1
foregroundColor to all of
ChildPlaceholder's text, using a field mask
to specify that only the foreground color of the element should change. This
request has the following outcomes:
- First paragraph: The new
foregroundColor
matches the inheritedforegroundColor
, so this style is unchanged and still inherits. - Second paragraph: The new
foregroundColor
doesn't match the inheritedforegroundColor
, so the second paragraph's foreground color is updated toDARK1
.
ChildPlaceholder's text content is now:
"text": {
"textElements": [
{ "startIndex": 0, "endIndex": 1,
"paragraphMarker": {
"style": {},
}
},
{ "startIndex": 0, "endIndex": 1,
"textRun": {
"content": "This is my first paragraph\n",
"style": {},
}
...
},
{ "startIndex": 1, "endIndex": 2,
"paragraphMarker": {
"style": {},
"bullet": {"nestingLevel": 1, "listId": "someListId", "glyph": "●" }
}
},
{ "startIndex": 1, "endIndex": 2,
"textRun": {
"content": "This paragraph is in a list\n",
"style": {"foregroundColor": {"opaqueColor": {"themeColor": "DARK1"} }, },
...
}
}
]
}
Bullet glyph text style
Like normal text, bullet glyphs have a text style that controls how the glyph is rendered. These text styles cannot be modified using the Slides API directly. However, if you use an UpdateTextStyleRequest to update a complete paragraph that includes a bullet, the Slides API updates the bullet glyph's text style to match.
Bullet glyph text styles follow a slightly different inheritance hierarchy than normal text styles.
- A bullet at a certain nesting level first inherits from the
TextStyle
set in theNestingLevel.bullet_style
field inside the bullet'sList
object. - It next inherits from the corresponding
NestingLevel.bullet_style
in its parent placeholder'sList
. - Finally it seeks to inherit from remaining parent placeholder objects.