UNPKG

chat

Version:

Unified chat abstraction for Slack, Teams, Google Chat, and Discord

273 lines (241 loc) 6.49 kB
--- title: Modals description: Modal form components for collecting user input. type: reference --- Modals display form dialogs that collect structured user input. Currently supported on Slack and Teams. ```typescript import { Modal, TextInput, Select, RadioSelect, SelectOption } from "chat"; ``` ## Modal Top-level container for a form dialog. Open a modal from an `onAction` or `onSlashCommand` handler using `event.openModal()`. ```typescript bot.onAction("open-form", async (event) => { await event.openModal( Modal({ callbackId: "feedback", title: "Submit Feedback", submitLabel: "Send", children: [ TextInput({ id: "comment", label: "Comment", multiline: true }), ], }) ); }); ``` <TypeTable type={{ callbackId: { description: 'Unique ID for routing to onModalSubmit/onModalClose handlers.', type: 'string', }, title: { description: 'Modal title displayed in the header.', type: 'string', }, submitLabel: { description: 'Label for the submit button.', type: 'string', default: '"Submit"', }, closeLabel: { description: 'Label for the close/cancel button.', type: 'string', default: '"Cancel"', }, notifyOnClose: { description: 'Whether to fire onModalClose when the user dismisses the modal.', type: 'boolean', default: 'false', }, callbackUrl: { description: 'URL to POST form values to when the modal is submitted.', type: 'string', }, privateMetadata: { description: 'Arbitrary string passed through the modal lifecycle (e.g., JSON context).', type: 'string', }, children: { description: 'Form input elements.', type: 'ModalChild[]', }, }} /> ## TextInput A text input field. ```typescript TextInput({ id: "name", label: "Your name", placeholder: "Enter your name", }) TextInput({ id: "description", label: "Description", multiline: true, maxLength: 500, optional: true, }) ``` <TypeTable type={{ id: { description: 'Input ID — used as the key in event.values.', type: 'string', }, label: { description: 'Label displayed above the input.', type: 'string', }, placeholder: { description: 'Placeholder text.', type: 'string', }, initialValue: { description: 'Pre-filled value.', type: 'string', }, multiline: { description: 'Render as a textarea.', type: 'boolean', default: 'false', }, optional: { description: 'Whether the field can be left empty.', type: 'boolean', default: 'false', }, maxLength: { description: 'Maximum character length.', type: 'number', }, }} /> ## Select Dropdown menu. ```typescript Select({ id: "priority", label: "Priority", placeholder: "Select priority", options: [ SelectOption({ label: "High", value: "high", description: "Urgent tasks" }), SelectOption({ label: "Medium", value: "medium" }), SelectOption({ label: "Low", value: "low" }), ], }) ``` <TypeTable type={{ id: { description: 'Input ID — used as the key in event.values.', type: 'string', }, label: { description: 'Label displayed above the select.', type: 'string', }, placeholder: { description: 'Placeholder text.', type: 'string', }, initialOption: { description: 'Pre-selected option value.', type: 'string', }, optional: { description: 'Whether the field can be left empty.', type: 'boolean', default: 'false', }, options: { description: 'Select options.', type: 'SelectOptionElement[]', }, }} /> ## ExternalSelect Dropdown that loads options dynamically from a handler as the user types. Slack-only. Pair with [`bot.onOptionsLoad`](/docs/api/chat#onoptionsload) to supply options. See [Modals → ExternalSelect](/docs/modals#externalselect) for a full example, grouped-options support, and Slack setup notes. ```typescript ExternalSelect({ id: "assignee", label: "Assignee", placeholder: "Search people", minQueryLength: 1, initialOption: { label: "Alice", value: "U123" }, }) ``` <TypeTable type={{ id: { description: 'Input ID — used as the key in event.values.', type: 'string', }, label: { description: 'Label displayed above the select.', type: 'string', }, placeholder: { description: 'Placeholder text.', type: 'string', }, minQueryLength: { description: 'Minimum characters before the loader fires (Slack default: 3).', type: 'number', }, initialOption: { description: 'Pre-selected option when the modal opens. Unlike static Select where initialOption is a value string, ExternalSelect needs the full label/value object since the loader has not run yet.', type: '{ label: string, value: string }', }, optional: { description: 'Whether the field can be left empty.', type: 'boolean', default: 'false', }, }} /> The loader registered via `bot.onOptionsLoad("assignee", handler)` returns either a flat `SelectOptionElement[]` or `OptionsLoadGroup[]` (`{ label, options }[]`) for grouped options. ## RadioSelect Radio button group for mutually exclusive choices. ```typescript RadioSelect({ id: "status", label: "Status", options: [ SelectOption({ label: "Open", value: "open" }), SelectOption({ label: "Closed", value: "closed" }), ], }) ``` Same props as `Select` (except `placeholder`). ## SelectOption An option used inside `Select` and `RadioSelect`. ```typescript SelectOption({ label: "High", value: "high", description: "Urgent tasks" }) ``` <TypeTable type={{ label: { description: 'Display text.', type: 'string', }, value: { description: 'Value sent in event.values when selected.', type: 'string', }, description: { description: 'Optional description shown below the label.', type: 'string', }, }} /> ## ModalChild types The `children` array in `Modal` accepts these element types: | Type | Created by | |------|-----------| | `TextInputElement` | `TextInput()` | | `SelectElement` | `Select()` | | `RadioSelectElement` | `RadioSelect()` | | `TextElement` | `Text()` — static text content | | `FieldsElement` | `Fields()` — key-value display |