Open interactive dialogs

This page describes how a Google Chat app can open dialogs to display user interfaces (UIs) and respond to users.

In Google Chat, add-ons appear to users as Google Chat apps. To learn more, see the Extend Google Chat overview.

Dialogs are windowed, card-based interfaces that open from a Chat space or message. The dialog and its contents are only visible to the user that opened it.

Chat apps can use dialogs to request and collect information from Chat users, including multi-step forms. For more details on building form inputs, see Collect and process information from users.

Prerequisites

Node.js

A Google Workspace add-on that extends Google Chat. To build one, complete the HTTP quickstart.

Apps Script

A Google Workspace add-on that extends Google Chat. To build one, complete the Apps Script quickstart.

Open a dialog

A dialog featuring a variety of different widgets.
Figure 1: A Chat app that opens a dialog to collect contact information.

This section explains how to respond and set up a dialog by doing the following:

  1. Trigger the dialog request from a user interaction.
  2. Handle the request by returning and opening a dialog.
  3. After users submit information, process the submission by either closing the dialog or returning another dialog.

Trigger a dialog request

A Chat app can only open dialogs to respond to a user interaction, such as a quick command, slash command, or a button click from a message in a card.

To respond to users with a dialog, a Chat app must build an interaction that triggers the dialog request, such as the following:

  • Respond to a quick command or a slash command. To trigger the request from a quick command or a slash command, you must check the Opens a dialog checkbox when configuring the quick command or slash command.
  • Respond to a button click in a message, either as part of a card or at the bottom of the message. To trigger the request from a button in a message, you configure the button's onClick action by setting its interaction to OPEN_DIALOG.
Button that triggers a dialog
Figure 2: A Chat app sends a message that prompts users to use the /addContact slash command.
The message also includes a button that users can click to trigger the command.

The following JSON shows how to trigger a dialog request from a button in a card message. To open the dialog, set the field onClick.action.interaction of the button to OPEN_DIALOG:

{
  "buttonList": { "buttons": [{
    "text": "BUTTON_TEXT",
    "onClick": { "action": {
      "function": "ACTION_FUNCTION",
      "interaction": "OPEN_DIALOG"
    }}
  }]}
}

Where BUTTON_TEXT is the text that displays in the button and ACTION_FUNCTION is the function that runs to open the initial dialog.

Open the initial dialog

When a user triggers a dialog request, your Chat app receives an event object with a payload that specifies that an dialogEventType object as REQUEST_DIALOG.

To open a dialog, your Chat app can respond to the request by returning a RenderActions object with the navigation pushCard to display a card. The card should contain any user interface (UI) elements, including one or more sections[] of widgets. To collect information from users, you can specify form input widgets and a button widget. To learn more about designing form inputs, see Collect and process information from users.

The following JSON shows how a Chat app returns a response that opens a dialog:

{
  "action": { "navigations": [{ "pushCard": { "sections": [{ "widgets": [{
    WIDGETS,
    { "buttonList": { "buttons": [{
      "text": "BUTTON_TEXT",
      "onClick": {
        "action": { "function": "ACTION_FUNCTION" }
      }
    }]}}
  }]}]}}]}
}

Where BUTTON_TEXT is the text that displays in the button (such as Next or Submit), WIDGETS represents one or more form input widgets, and ACTION_FUNCTION is the action's callback function that runs when users click a button.

Handle the dialog submission

When users click a button that submits a dialog, your Chat app receives an event object with an ButtonClickedPayload object. In the payload, the dialogEventType is set to SUBMIT_DIALOG.

Your Chat app must handle the event object by doing one of the following:

Optional: Return another dialog

After users submit the initial dialog, Chat apps can return one or more additional dialogs to help users review information before submitting, complete multi-step forms, or populate form content dynamically.

To process the data that users input, the Chat app handles the data in the event's commonEventObject.formInputs object. To learn more about retrieving values from input widgets, see Collect and process information from users.

To keep track of any data that users input from the initial dialog, you must add parameters to the button that opens the next dialog. For details, see Transfer data to another card.

In this example, a Chat app opens an initial dialog that leads to a second dialog for confirmation before submitting:

Node.js

/**
 * Google Cloud Function that handles all Google Workspace Add On events for
 * the contact manager app.
 *
 * @param {Object} req Request sent from Google Chat space
 * @param {Object} res Response to send back
 */
exports.contactManager = function contactManager(req, res) {
  const chatEvent = req.body.chat;
  // Handle MESSAGE events
  if(chatEvent.messagePayload) {
    return res.send(handleMessage(req.body));
  // Handle button clicks
  } else if(chatEvent.buttonClickedPayload) {
    switch(req.body.commonEventObject.parameters.actionName) {
        case "openInitialDialog":
            return res.send(openInitialDialog(req.body));
        case "openConfirmationDialog":
            return res.send(openConfirmationDialog(req.body));
        case "submitDialog":
            return res.send(submitDialog(req.body));
    }
  }
};

/**
 * Responds to a message in Google Chat.
 *
 * @param {Object} event The event object from the Google Workspace Add-on.
 * @return {Object} response that handles dialogs.
 */
function handleMessage(event) {
  // Reply with a message that contains a button to open the initial dialog
  return { hostAppDataAction: { chatDataAction: { createMessageAction: { message: {
    text: "To add a contact, use the `ADD CONTACT` button below.",
    accessoryWidgets: [{ buttonList: { buttons: [{
      text: "ADD CONTACT",
      onClick: { action: {
        // Use runtime environment variable set with self URL
        function: process.env.BASE_URL,
        parameters: [{ key: "actionName", value: "openInitialDialog" }],
        interaction: "OPEN_DIALOG"
      }}
    }]}}]
  }}}}};
}

/**
 * Opens the initial step of the dialog that lets users add contact details.
 *
 * @param {Object} event The event object from the Google Workspace Add-on.
 * @return {Object} open the dialog.
 */
function openInitialDialog(event) {
  return { action: { navigations: [{ pushCard: { sections: [{ widgets: [{
    textInput: {
      name: "contactName",
      label: "First and last name",
      type: "SINGLE_LINE"
    }},
    WIDGETS, {
    buttonList: { buttons: [{
      text: "NEXT",
      onClick: { action: {
        // Use runtime environment variable set with self URL
        function: process.env.BASE_URL,
        parameters: [{ key: "actionName", value: "openConfirmationDialog" }]
      }}
    }]}}
  ]}]}}]}};
}

/**
 * Opens the second step of the dialog that lets users confirm details.
 *
 * @param {Object} event The event object from the Google Workspace Add-on.
 * @return {Object} update the dialog.
 */
function openConfirmationDialog(event) {
  // Retrieve the form input values
  const name = event.commonEventObject.formInputs["contactName"].stringInputs.value[0];
  return { action: { navigations: [{ pushCard: { sections: [{ widgets: [{
    // Display the input values for confirmation
    textParagraph: { text: "<b>Name:</b> " + name }},
    WIDGETS, {
    buttonList: { buttons: [{
      text: "SUBMIT",
      onClick: { action: {
        // Use runtime environment variable set with self URL
        function: process.env.BASE_URL,
        parameters: [{
          key: "actionName", value: "submitDialog" }, {
          // Pass input values as parameters for last dialog step (submission)
          key: "contactName", value: name
        }]
      }}
    }]}}]
  }]}}]}};
}

Apps Script

This example sends a card message by returning card JSON. You can also use the Apps Script card service.

/**
 * Responds to a message in Google Chat.
 *
 * @param {Object} event The event object from the Google Workspace Add-on.
 * @return {Object} response that handles dialogs.
 */
function onMessage(event) {
  // Reply with a message that contains a button to open the initial dialog
  return { hostAppDataAction: { chatDataAction: { createMessageAction: { message: {
    text: "To add a contact, use the `ADD CONTACT` button below.",
    accessoryWidgets: [{ buttonList: { buttons: [{
      text: "ADD CONTACT",
      onClick: { action: {
        function: "openInitialDialog",
        interaction: "OPEN_DIALOG"
      }}
    }]}}]
  }}}}};
}

/**
 * Opens the initial step of the dialog that lets users add contact details.
 *
 * @param {Object} event The event object from the Google Workspace Add-on.
 * @return {Object} open the dialog.
 */
function openInitialDialog(event) {
  return { action: { navigations: [{ pushCard: { sections: [{ widgets: [{
    textInput: {
      name: "contactName",
      label: "First and last name",
      type: "SINGLE_LINE"
    }},
    WIDGETS, {
    buttonList: { buttons: [{
      text: "NEXT",
      onClick: { action: { function : "openConfirmationDialog" }}
    }]}}
  ]}]}}]}};
}

/**
 * Opens the second step of the dialog that lets users confirm details.
 *
 * @param {Object} event The event object from the Google Workspace Add-on.
 * @return {Object} update the dialog.
 */
function openConfirmationDialog(event) {
  // Retrieve the form input values
  const name = event.commonEventObject.formInputs["contactName"].stringInputs.value[0];
  return { action: { navigations: [{ pushCard: { sections: [{ widgets: [{
    // Display the input values for confirmation
    textParagraph: { text: "<b>Name:</b> " + name }},
    WIDGETS, {
    buttonList: { buttons: [{
      text: "SUBMIT",
      onClick: { action: {
        function: "submitDialog",
        // Pass input values as parameters for last dialog step (submission)
        parameters: [{ key: "contactName", value: name }]
      }}
    }]}}]
  }]}}]}};
}

Where WIDGETS represents any other form input widgets.

Close the dialog

When users click a submit button on a dialog, your Chat app executes its associated action and provides the event object with buttonClickedPayload set to the following:

  • isDialogEvent is true.
  • dialogEventType is SUBMIT_DIALOG.

The Chat app should return a RenderActions object with EndNavigation set to CLOSE_DIALOG.

Optional: Display a notification

When you close the dialog, you can also display a text notification.

To display a notification, return the RenderActions object with the field notification set.

The following example checks that parameters are valid and closes the dialog with text notification depending on the outcome:

Node.js

/**
 * Handles submission and closes the dialog.
 *
 * @param {Object} event The event object from the Google Workspace Add-on.
 * @return {Object} close the dialog with a status in text notification.
 */
function submitDialog(event) {
  // Validate the parameters.
  if (!event.commonEventObject.parameters["contactName"]) {
    return { action: {
      navigations: [{ endNavigation: "CLOSE_DIALOG"}],
      notification: { text: "Failure, the contact name was missing!" }
    }};
  }

  return { action: {
    navigations: [{ endNavigation: "CLOSE_DIALOG"}],
    notification: { text: "Success, the contact was added!" }
  }};
}

Apps Script

/**
 * Handles submission and closes the dialog.
 *
 * @param {Object} event The event object from the Google Workspace Add-on.
 * @return {Object} close the dialog with a status in text notification.
 */
function submitDialog(event) {
  // Validate the parameters.
  if (!event.commonEventObject.parameters["contactName"]) {
    return { action: {
      navigations: [{ endNavigation: "CLOSE_DIALOG"}],
      notification: { text: "Failure, the contact name was missing!" }
    }};
  }

  return { action: {
    navigations: [{ endNavigation: "CLOSE_DIALOG"}],
    notification: { text: "Success, the contact was added!" }
  }};
}

For details about passing parameters between dialogs, see Transfer data to another card.

Optional: Send a confirmation message

When you close the dialog, you can also send a new message, or update an existing one.

To send a new message, return a DataActions object with the field CreateMessageAction set with the new message. For example, to close the dialog and send a text message, return the following:

{ "hostAppDataAction": { "chatDataAction": { "createMessageAction": { "message": {
  "text": "Your information has been submitted."
}}}}}

To update a message after the user submits a dialog, return a DataActions object that contains one of the following actions:

Troubleshoot

When a Google Chat app or card returns an error, the Chat interface surfaces a message saying "Something went wrong." or "Unable to process your request." Sometimes the Chat UI doesn't display any error message, but the Chat app or card produces an unexpected result; for example, a card message might not appear.

Although an error message might not display in the Chat UI, descriptive error messages and log data are available to help you fix errors when error logging for Chat apps is turned on. For help viewing, debugging, and fixing errors, see Troubleshoot and fix Google Chat errors.