The Google Docs API lets you programmatically create, insert, update, read, and manage dropdown chips within Google Docs documents.

## What are dropdown chips?

[Dropdown chips](https://support.google.com/docs/answer/12319513) in Google Docs provide users with an interactive, customizable selection menu inline within document text. Users can click a dropdown chip to select from a predefined list of options, each with its own display text and color styling. Dropdown chips are frequently used for project tracking, status updates, review workflows, and approval stages.

Through the Docs API, you can:

- Define reusable dropdown templates with customized titles, option names, and colors.
- Insert dropdown chips at a valid character location.
- Update the selected option of an individual dropdown chip instance.
- Modify shared dropdown definitions in place, updating all referencing chips simultaneously.
- Safely replace or retire options while maintaining referential integrity across existing chips.
- Delete unused dropdown templates.

## Architecture: definitions and instances

In the Docs API, dropdown chips have definitions and instances. A
definition sets options for a dropdown instance. A dropdown instance is a
dropdown that people can interact with, and it saves information about
selections.

The Docs API separates the dropdown template configuration from the inline dropdown chip instances:

1. **DropdownDefinition** : A tab-level template that defines the dropdown title and the collection of selectable choices ([`DropdownOption`](https://developers.google.com/workspace/docs/api/reference/rest/v1/documents#DropdownOption)). It does not reside at a specific character offset in the document; instead, it is stored in the tab's definition map: [`document.tabs[].documentTab.dropdownDefinitions`](https://developers.google.com/workspace/docs/api/reference/rest/v1/documents#DocumentTab.FIELDS.dropdown_definitions).
2. **Dropdown** : An individual chip instance embedded inline within a paragraph element ([`ParagraphElement.dropdown`](https://developers.google.com/workspace/docs/api/reference/rest/v1/documents#Dropdown)). Each dropdown instance references a `dropdownDefinitionId` and stores its own active `selectedOptionId`.

![Decoupled architecture of dropdown definitions and chip instances.](https://developers.google.com/static/workspace/docs/api/images/dropdown-hierarchy-erd.svg) **Figure 1.** Decoupled architecture of dropdown definitions and chip instances.

Modifying a `DropdownDefinition` (e.g., adding an option or renaming the title) updates all referencing chips across the tab without requiring updates to every individual element.

Each `Dropdown` instance tracks its own `selectedOptionId`. Mutating an individual chip's selected value affects only that specific instance.

### ID format and validation rules

User-provided IDs must adhere to strict format, prefix, and length specifications:

| Identifier | Mandatory Prefix | Validation regular expression | Length Limit | Example |
|---|---|---|---|---|
| **Dropdown definition ID** (`dropdownDefinitionId`) | `kix.` | `^kix\.[a-zA-Z0-9_-]{2,14}$` | 6--18 characters | `kix.review_status` |
| **Dropdown option ID** (`optionId`) | `dropdownItem.` | `^dropdownItem\.[a-zA-Z0-9_-]{2,14}$` | 15--27 characters | `dropdownItem.pending` |

> [!NOTE]
> **Note:** If you omit `dropdownDefinitionId` or `optionId` when creating a definition, the server automatically generates a unique permanent ID (for example, `kix.8a7b6c5d` and `dropdownItem.ydcttxh1yt15`). Dropdown chip instance IDs (`dropdownId`) are always generated by the server when `InsertDropdownRequest` executes and are returned in [`InsertDropdownResponse`](https://developers.google.com/workspace/docs/api/reference/rest/v1/documents/response#InsertDropdownResponse).

### Generate user-provided IDs

To generate IDs that adhere to the mandatory prefix and regular expression
requirements, use the following helper functions. These helpers generate
lowercase base-36 alphanumeric suffixes, matching the format generated by the
Google Docs UI:

### Python

    import random
    import string

    def generate_dropdown_definition_id(suffix_len: int = 8) -> str:
        """Generates a valid user-provided DropdownDefinition ID (6-18 chars, starting with 'kix.')."""
        chars = string.ascii_lowercase + string.digits
        suffix = "".join(random.choices(chars, k=max(2, min(suffix_len, 14))))
        return f"kix.{suffix}"

    def generate_dropdown_option_id(suffix_len: int = 8) -> str:
        """Generates a valid user-provided DropdownOption ID (15-27 chars, starting with 'dropdownItem.')."""
        chars = string.ascii_lowercase + string.digits
        suffix = "".join(random.choices(chars, k=max(2, min(suffix_len, 14))))
        return f"dropdownItem.{suffix}"

### Java

    import java.security.SecureRandom;

    public final class DropdownIdGenerator {
      private static final String BASE36_CHARS =
          "abcdefghijklmnopqrstuvwxyz0123456789";
      private static final SecureRandom RANDOM = new SecureRandom();

      private DropdownIdGenerator() {}

      /** Generates a valid user-provided DropdownDefinition ID (6-18 chars, starting with "kix."). */
      public static String generateDefinitionId(int suffixLength) {
        int length = Math.max(2, Math.min(suffixLength, 14));
        StringBuilder sb = new StringBuilder("kix.");
        for (int i = 0; i < length; i++) {
          sb.append(BASE36_CHARS.charAt(RANDOM.nextInt(BASE36_CHARS.length())));
        }
        return sb.toString();
      }

      /** Generates a valid user-provided DropdownOption ID (15-27 chars, starting with "dropdownItem."). */
      public static String generateOptionId(int suffixLength) {
        int length = Math.max(2, Math.min(suffixLength, 14));
        StringBuilder sb = new StringBuilder("dropdownItem.");
        for (int i = 0; i < length; i++) {
          sb.append(BASE36_CHARS.charAt(RANDOM.nextInt(BASE36_CHARS.length())));
        }
        return sb.toString();
      }
    }

## Create and insert dropdown chips

### Single-batch creation (recommended)

The most efficient pattern combines [`CreateDropdownDefinitionRequest`](https://developers.google.com/workspace/docs/api/reference/rest/v1/documents/request#CreateDropdownDefinitionRequest) and [`InsertDropdownRequest`](https://developers.google.com/workspace/docs/api/reference/rest/v1/documents/request#InsertDropdownRequest) in one `documents.batchUpdate` call.

The following code sample creates a "Review Status" dropdown definition with three color-coded choices using user-provided IDs, and inserts an instance at the end of the document:

### Python

    requests = [
        {
            "createDropdownDefinition": {
                "dropdownDefinition": {
                    "dropdownDefinitionId": "kix.review_status",
                    "dropdownDefinitionProperties": {
                        "title": "Review Status",
                        "options": [
                            {
                                "optionId": "dropdownItem.pending",
                                "displayValue": "Pending Review",
                                "textStyle": {
                                    "backgroundColor": {
                                        "color": {"rgbColor": {"red": 0.99, "green": 0.90, "blue": 0.65}}
                                    },
                                    "foregroundColor": {
                                        "color": {"rgbColor": {"red": 0.45, "green": 0.30, "blue": 0.0}}
                                    },
                                },
                            },
                            {
                                "optionId": "dropdownItem.approved",
                                "displayValue": "Approved",
                                "textStyle": {
                                    "backgroundColor": {
                                        "color": {"rgbColor": {"red": 0.85, "green": 0.95, "blue": 0.85}}
                                    },
                                    "foregroundColor": {
                                        "color": {"rgbColor": {"red": 0.08, "green": 0.40, "blue": 0.15}}
                                    },
                                },
                            },
                            {
                                "optionId": "dropdownItem.rejected",
                                "displayValue": "Needs Changes",
                                "textStyle": {
                                    "backgroundColor": {
                                        "color": {"rgbColor": {"red": 0.98, "green": 0.84, "blue": 0.84}}
                                    },
                                    "foregroundColor": {
                                        "color": {"rgbColor": {"red": 0.65, "green": 0.10, "blue": 0.10}}
                                    },
                                },
                            },
                        ],
                    },
                }
            }
        },
        {
            "insertDropdown": {
                "endOfSegmentLocation": {},
                "dropdownDefinitionId": "kix.review_status",
                "selectedOptionId": "dropdownItem.pending",
            }
        },
    ]

    result = service.documents().batchUpdate(
        documentId=DOCUMENT_ID,
        body={"requests": requests}
    ).execute()

### Java

    List<Request> requests = new ArrayList<>();

    List<DropdownOption> options = Arrays.asList(
        new DropdownOption()
            .setOptionId("dropdownItem.pending")
            .setDisplayValue("Pending Review")
            .setTextStyle(new TextStyle()
                .setBackgroundColor(new OptionalColor().setColor(
                    new Color().setRgbColor(new RgbColor().setRed(0.99f).setGreen(0.90f).setBlue(0.65f))))
                .setForegroundColor(new OptionalColor().setColor(
                    new Color().setRgbColor(new RgbColor().setRed(0.45f).setGreen(0.30f).setBlue(0.0f))))),
        new DropdownOption()
            .setOptionId("dropdownItem.approved")
            .setDisplayValue("Approved")
            .setTextStyle(new TextStyle()
                .setBackgroundColor(new OptionalColor().setColor(
                    new Color().setRgbColor(new RgbColor().setRed(0.85f).setGreen(0.95f).setBlue(0.85f))))
                .setForegroundColor(new OptionalColor().setColor(
                    new Color().setRgbColor(new RgbColor().setRed(0.08f).setGreen(0.40f).setBlue(0.15f))))),
        new DropdownOption()
            .setOptionId("dropdownItem.rejected")
            .setDisplayValue("Needs Changes")
            .setTextStyle(new TextStyle()
                .setBackgroundColor(new OptionalColor().setColor(
                    new Color().setRgbColor(new RgbColor().setRed(0.98f).setGreen(0.84f).setBlue(0.84f))))
                .setForegroundColor(new OptionalColor().setColor(
                    new Color().setRgbColor(new RgbColor().setRed(0.65f).setGreen(0.10f).setBlue(0.10f))))));

    DropdownDefinition definition = new DropdownDefinition()
        .setDropdownDefinitionId("kix.review_status")
        .setDropdownDefinitionProperties(new DropdownDefinitionProperties()
            .setTitle("Review Status")
            .setOptions(options));

    requests.add(new Request().setCreateDropdownDefinition(
        new CreateDropdownDefinitionRequest().setDropdownDefinition(definition)));

    requests.add(new Request().setInsertDropdown(
        new InsertDropdownRequest()
            .setEndOfSegmentLocation(new EndOfSegmentLocation())
            .setDropdownDefinitionId("kix.review_status")
            .setSelectedOptionId("dropdownItem.pending")));

    BatchUpdateDocumentRequest body = new BatchUpdateDocumentRequest().setRequests(requests);
    BatchUpdateDocumentResponse response = docsService.documents()
        .batchUpdate(DOCUMENT_ID, body)
        .execute();

### Dropdown validation rules and limits

When creating or modifying dropdown definitions, the following constraints apply:

- **Option Count** : A dropdown definition must have between **2** and **50** options.
- **Title Length** : The definition `title` cannot be empty and must not exceed **200** characters.
- **Display Value Length** : Each option's `displayValue` cannot be empty and must not exceed **200** characters.
- **Option Styling** : Only `foregroundColor` and `backgroundColor` are supported in `DropdownOption.textStyle`. Setting other style properties returns a `400 Bad Request` error.
- **Default Selection** : In `InsertDropdownRequest`, if `selectedOptionId` is omitted, the chip defaults to the first option defined in the `DropdownDefinition`.

## Update an individual dropdown chip selection

To change the selected option of an existing dropdown chip instance without altering its template or other chips, use [`UpdateDropdownPropertiesRequest`](https://developers.google.com/workspace/docs/api/reference/rest/v1/documents/request#UpdateDropdownPropertiesRequest):

- `dropdownId`: (Required) The ID of the specific dropdown chip instance to update.
- `tabId`: The ID of the tab containing the dropdown (defaults to the first tab if omitted).
- `fields`: Set to `"selectedOptionId"`.

The following code sample updates the active selection of a dropdown chip to `"dropdownItem.approved"`:

### Python

    requests = [
        {
            "updateDropdownProperties": {
                "dropdownId": "kix.chip_abc1",
                "tabId": "t.0",
                "dropdownProperties": {
                    "selectedOptionId": "dropdownItem.approved",
                },
                "fields": "selectedOptionId",
            }
        }
    ]

    result = service.documents().batchUpdate(
        documentId=DOCUMENT_ID,
        body={"requests": requests}
    ).execute()

### Java

    List<Request> requests = new ArrayList<>();
    requests.add(new Request().setUpdateDropdownProperties(
        new UpdateDropdownPropertiesRequest()
            .setDropdownId("kix.chip_abc1")
            .setTabId("t.0")
            .setDropdownProperties(new DropdownProperties()
                .setSelectedOptionId("dropdownItem.approved"))
            .setFields("selectedOptionId")));

    BatchUpdateDocumentRequest body = new BatchUpdateDocumentRequest().setRequests(requests);
    BatchUpdateDocumentResponse response = docsService.documents()
        .batchUpdate(DOCUMENT_ID, body)
        .execute();

## Update dropdown definitions and options

To modify the template itself (title, options list, display labels, or colors), use [`UpdateDropdownDefinitionPropertiesRequest`](https://developers.google.com/workspace/docs/api/reference/rest/v1/documents/request#UpdateDropdownDefinitionPropertiesRequest). Updating a definition automatically updates all dropdown chips referencing it across the tab.

### Full list replacement for options

When `dropdownDefinitionProperties.options` is included in the `fields` mask, the request performs a **full list replacement**. You must supply the complete list of options in the chosen order. The server diffs the incoming list against the current definition:

- **New option** : Including an option without an `optionId` (or with a new user-provided `optionId`) adds it to the definition.
- **Updated option** : Providing an existing `optionId` with modified `displayValue` or `textStyle` updates that option in place.
- **Reordered options**: The options list is saved in the exact sequence supplied in the request.
- **Deleted option** : Omitting an existing `optionId` deletes that option from the definition.

### Referential integrity and option replacement

If an option being deleted is selected in any dropdown chip within the document, you **must** supply a mapping in `selectedOptionIdReplacements` (`map<string, string>`). The keys are the IDs of the options being deleted, and the values are the IDs of the replacement options.

> [!WARNING]
> **Important:** If an active option is deleted without providing an entry in `selectedOptionIdReplacements`, the server rejects the request with a `400 Bad Request` error. Options that are not selected in any chip in the document don't require a replacement entry.

The following code sample demonstrates how to update a dropdown definition with option replacements:

### Python

    requests = [
        {
            "updateDropdownDefinitionProperties": {
                "dropdownDefinitionId": "kix.review_status",
                "tabId": "t.0",
                "dropdownDefinitionProperties": {
                    "title": "Editorial Review Status",
                    "options": [
                        {
                            "optionId": "dropdownItem.approved",
                            "displayValue": "Approved",
                            "textStyle": {
                                "backgroundColor": {
                                    "color": {"rgbColor": {"red": 0.85, "green": 0.95, "blue": 0.85}}
                                },
                                "foregroundColor": {
                                    "color": {"rgbColor": {"red": 0.08, "green": 0.40, "blue": 0.15}}
                                },
                            },
                        },
                        {
                            "optionId": "dropdownItem.rejected",
                            "displayValue": "Changes Requested",
                            "textStyle": {
                                "backgroundColor": {
                                    "color": {"rgbColor": {"red": 0.98, "green": 0.84, "blue": 0.84}}
                                },
                                "foregroundColor": {
                                    "color": {"rgbColor": {"red": 0.65, "green": 0.10, "blue": 0.10}}
                                },
                            },
                        },
                    ],
                },
                "selectedOptionIdReplacements": {
                    "dropdownItem.pending": "dropdownItem.rejected"
                },
                "fields": "title,options",
            }
        }
    ]

    result = service.documents().batchUpdate(
        documentId=DOCUMENT_ID,
        body={"requests": requests}
    ).execute()

### Java

    List<DropdownOption> updatedOptions = Arrays.asList(
        new DropdownOption()
            .setOptionId("dropdownItem.approved")
            .setDisplayValue("Approved")
            .setTextStyle(new TextStyle()
                .setBackgroundColor(new OptionalColor().setColor(
                    new Color().setRgbColor(new RgbColor().setRed(0.85f).setGreen(0.95f).setBlue(0.85f))))
                .setForegroundColor(new OptionalColor().setColor(
                    new Color().setRgbColor(new RgbColor().setRed(0.08f).setGreen(0.40f).setBlue(0.15f))))),
        new DropdownOption()
            .setOptionId("dropdownItem.rejected")
            .setDisplayValue("Changes Requested")
            .setTextStyle(new TextStyle()
                .setBackgroundColor(new OptionalColor().setColor(
                    new Color().setRgbColor(new RgbColor().setRed(0.98f).setGreen(0.84f).setBlue(0.84f))))
                .setForegroundColor(new OptionalColor().setColor(
                    new Color().setRgbColor(new RgbColor().setRed(0.65f).setGreen(0.10f).setBlue(0.10f))))));

    Map<String, String> replacements = new HashMap<>();
    replacements.put("dropdownItem.pending", "dropdownItem.rejected");

    List<Request> requests = new ArrayList<>();
    requests.add(new Request().setUpdateDropdownDefinitionProperties(
        new UpdateDropdownDefinitionPropertiesRequest()
            .setDropdownDefinitionId("kix.review_status")
            .setTabId("t.0")
            .setDropdownDefinitionProperties(new DropdownDefinitionProperties()
                .setTitle("Editorial Review Status")
                .setOptions(updatedOptions))
            .setSelectedOptionIdReplacements(replacements)
            .setFields("title,options")));

    BatchUpdateDocumentRequest body = new BatchUpdateDocumentRequest().setRequests(requests);
    BatchUpdateDocumentResponse response = docsService.documents()
        .batchUpdate(DOCUMENT_ID, body)
        .execute();

## Delete a dropdown definition

To remove an unused dropdown template, use [`DeleteDropdownDefinitionRequest`](https://developers.google.com/workspace/docs/api/reference/rest/v1/documents/request#DeleteDropdownDefinitionRequest).

> [!CAUTION]
> **Caution:** If any dropdown chips in the document still reference the `dropdownDefinitionId`, the request fails with a `400 Bad Request` error. You must delete or retarget all dropdown chip instances referencing the definition before deleting it.

The following code sample demonstrates how to delete a dropdown definition:

### Python

    requests = [
        {
            "deleteDropdownDefinition": {
                "dropdownDefinitionId": "kix.review_status",
                "tabId": "t.0",
            }
        }
    ]

    result = service.documents().batchUpdate(
        documentId=DOCUMENT_ID,
        body={"requests": requests}
    ).execute()

### Java

    List<Request> requests = new ArrayList<>();
    requests.add(new Request().setDeleteDropdownDefinition(
        new DeleteDropdownDefinitionRequest()
            .setDropdownDefinitionId("kix.review_status")
            .setTabId("t.0")));

    BatchUpdateDocumentRequest body = new BatchUpdateDocumentRequest().setRequests(requests);
    BatchUpdateDocumentResponse response = docsService.documents()
        .batchUpdate(DOCUMENT_ID, body)
        .execute();

## Error handling and troubleshooting

Common error conditions and resolutions:

| Status Code | Cause | Resolution |
|---|---|---|
| `400 INVALID_ARGUMENT` | Invalid ID prefix or regular expression format. | Ensure `dropdownDefinitionId` begins with `kix.` (6--18 chars) and `optionId` begins with `dropdownItem.` (15--27 chars). |
| `400 INVALID_ARGUMENT` | Option count out of bounds. | A dropdown definition must contain between 2 and 50 options. |
| `400 INVALID_ARGUMENT` | Title or display value is empty or exceeds 200 characters. | Provide a non-empty string between 1 and 200 characters. |
| `400 INVALID_ARGUMENT` | Unsupported text style property in option. | Only `foregroundColor` and `backgroundColor` are supported on dropdown options. Remove font, size, or other attributes. |
| `400 INVALID_ARGUMENT` | Missing option replacement mapping on delete. | When deleting an option that is selected by any chip, provide a valid replacement in `selectedOptionIdReplacements`. |
| `400 INVALID_ARGUMENT` | Attempted to delete a definition in use. | Delete or retarget all dropdown chip instances referencing the definition before deleting it. |
| `400 INVALID_ARGUMENT` | Duplicate user-provided ID. | Ensure user-provided IDs are unique within the document tab. |

## Related topics

- [Work with tabs](https://developers.google.com/workspace/docs/api/how-tos/tabs)
- [Format text](https://developers.google.com/workspace/docs/api/how-tos/format-text)
- [Work with comments and suggestions](https://developers.google.com/workspace/docs/api/how-tos/suggestions)
- [REST Resource: documents.request](https://developers.google.com/workspace/docs/api/reference/rest/v1/documents/request)
- [REST Resource: documents](https://developers.google.com/workspace/docs/api/reference/rest/v1/documents)
- [REST Resource: documents.batchUpdate](https://developers.google.com/workspace/docs/api/reference/rest/v1/documents/batchUpdate)