0
# Views and Modals
1
2
Views define the structure of Slack's interactive surfaces including modals, App Home tabs, and workflow step configurations. They provide the foundation for building rich user interfaces within Slack.
3
4
## Capabilities
5
6
### View Types
7
8
Union type covering all supported view types.
9
10
```typescript { .api }
11
type View = HomeView | ModalView | WorkflowStepView;
12
```
13
14
### Base View Interface
15
16
Common properties shared by all view types.
17
18
```typescript { .api }
19
interface BaseView {
20
blocks: AnyBlock[];
21
private_metadata?: string;
22
callback_id?: string;
23
external_id?: string;
24
}
25
```
26
27
### Modal View
28
29
Interactive modal dialogs with titles, submit/close buttons, and content blocks.
30
31
```typescript { .api }
32
interface ModalView extends BaseView {
33
type: 'modal';
34
title: PlainTextElement;
35
close?: PlainTextElement;
36
submit?: PlainTextElement;
37
clear_on_close?: boolean;
38
notify_on_close?: boolean;
39
}
40
```
41
42
**Usage Example:**
43
44
```typescript
45
import { ModalView, InputBlock, PlainTextInput } from "@slack/types";
46
47
const modal: ModalView = {
48
type: "modal",
49
title: {
50
type: "plain_text",
51
text: "User Registration"
52
},
53
submit: {
54
type: "plain_text",
55
text: "Submit"
56
},
57
close: {
58
type: "plain_text",
59
text: "Cancel"
60
},
61
blocks: [
62
{
63
type: "input",
64
block_id: "name_input",
65
label: {
66
type: "plain_text",
67
text: "Full Name"
68
},
69
element: {
70
type: "plain_text_input",
71
action_id: "name_value",
72
placeholder: {
73
type: "plain_text",
74
text: "Enter your full name"
75
}
76
}
77
},
78
{
79
type: "input",
80
block_id: "email_input",
81
label: {
82
type: "plain_text",
83
text: "Email Address"
84
},
85
element: {
86
type: "email_text_input",
87
action_id: "email_value",
88
placeholder: {
89
type: "plain_text",
90
text: "your.email@example.com"
91
}
92
}
93
}
94
],
95
callback_id: "user_registration_modal",
96
private_metadata: "registration_flow_v1"
97
};
98
```
99
100
### Home View
101
102
App Home tab interface for displaying custom content in the user's App Home.
103
104
```typescript { .api }
105
interface HomeView extends BaseView {
106
type: 'home';
107
}
108
```
109
110
**Usage Example:**
111
112
```typescript
113
import { HomeView, SectionBlock, HeaderBlock } from "@slack/types";
114
115
const homeView: HomeView = {
116
type: "home",
117
blocks: [
118
{
119
type: "header",
120
text: {
121
type: "plain_text",
122
text: "Welcome to Your Dashboard"
123
}
124
},
125
{
126
type: "section",
127
text: {
128
type: "mrkdwn",
129
text: "Here's a summary of your recent activity:"
130
}
131
},
132
{
133
type: "section",
134
fields: [
135
{
136
type: "mrkdwn",
137
text: "*Tasks Completed:*\n25"
138
},
139
{
140
type: "mrkdwn",
141
text: "*Messages Sent:*\n142"
142
}
143
]
144
},
145
{
146
type: "actions",
147
elements: [
148
{
149
type: "button",
150
text: {
151
type: "plain_text",
152
text: "View Reports"
153
},
154
action_id: "view_reports",
155
style: "primary"
156
},
157
{
158
type: "button",
159
text: {
160
type: "plain_text",
161
text: "Settings"
162
},
163
action_id: "open_settings"
164
}
165
]
166
}
167
]
168
};
169
```
170
171
### Workflow Step View (Deprecated)
172
173
Configuration modal for legacy Workflow Steps from Apps.
174
175
```typescript { .api }
176
interface WorkflowStepView extends BaseView {
177
type: 'workflow_step';
178
submit_disabled?: boolean;
179
}
180
```
181
182
**Note**: Workflow Steps from Apps are deprecated and will no longer be executed starting September 12, 2024.
183
184
## View Properties
185
186
### Blocks Array
187
188
All views contain an array of blocks that define their content structure.
189
190
```typescript { .api }
191
blocks: AnyBlock[];
192
```
193
194
The blocks array can contain any valid Block Kit blocks:
195
- `ActionsBlock` - Interactive elements
196
- `ContextBlock` - Contextual information
197
- `DividerBlock` - Visual separators
198
- `HeaderBlock` - Section headers
199
- `ImageBlock` - Image displays
200
- `InputBlock` - Form inputs (modals only)
201
- `SectionBlock` - Text content with optional accessories
202
- `RichTextBlock` - Formatted rich text
203
- `VideoBlock` - Embedded videos
204
205
### Private Metadata
206
207
String data passed to interaction payloads for maintaining state.
208
209
```typescript { .api }
210
private_metadata?: string;
211
```
212
213
**Usage Example:**
214
215
```typescript
216
const modal: ModalView = {
217
// ... other properties
218
private_metadata: JSON.stringify({
219
user_id: "U123456",
220
flow_step: "confirmation",
221
original_message_ts: "1609459200.000300"
222
})
223
};
224
```
225
226
### Callback ID
227
228
Identifier for recognizing view interactions and submissions.
229
230
```typescript { .api }
231
callback_id?: string;
232
```
233
234
### External ID
235
236
Custom identifier unique per team for external reference.
237
238
```typescript { .api }
239
external_id?: string;
240
```
241
242
## Modal-Specific Properties
243
244
### Title
245
246
Required title displayed in modal header.
247
248
```typescript { .api }
249
title: PlainTextElement;
250
```
251
252
### Submit Button
253
254
Optional submit button text (required when input blocks are present).
255
256
```typescript { .api }
257
submit?: PlainTextElement;
258
```
259
260
### Close Button
261
262
Optional close button text.
263
264
```typescript { .api }
265
close?: PlainTextElement;
266
```
267
268
### Clear on Close
269
270
When true, clicking close clears all modal views and closes the modal.
271
272
```typescript { .api }
273
clear_on_close?: boolean;
274
```
275
276
### Notify on Close
277
278
When true, sends `view_closed` event when user clicks close button.
279
280
```typescript { .api }
281
notify_on_close?: boolean;
282
```
283
284
## Modal Interaction Patterns
285
286
Modals support several interaction patterns:
287
288
### Form Collection
289
290
Use input blocks to collect structured data from users:
291
292
```typescript
293
const formModal: ModalView = {
294
type: "modal",
295
title: { type: "plain_text", text: "Project Details" },
296
submit: { type: "plain_text", text: "Create Project" },
297
blocks: [
298
{
299
type: "input",
300
label: { type: "plain_text", text: "Project Name" },
301
element: {
302
type: "plain_text_input",
303
action_id: "project_name"
304
}
305
},
306
{
307
type: "input",
308
label: { type: "plain_text", text: "Team Members" },
309
element: {
310
type: "multi_users_select",
311
action_id: "team_members",
312
placeholder: { type: "plain_text", text: "Select team members" }
313
}
314
},
315
{
316
type: "input",
317
label: { type: "plain_text", text: "Due Date" },
318
element: {
319
type: "datepicker",
320
action_id: "due_date"
321
}
322
}
323
]
324
};
325
```
326
327
### Multi-Step Workflows
328
329
Use `private_metadata` to track workflow state across multiple modal views:
330
331
```typescript
332
const step1Modal: ModalView = {
333
type: "modal",
334
title: { type: "plain_text", text: "Setup - Step 1 of 3" },
335
submit: { type: "plain_text", text: "Next" },
336
blocks: [/* step 1 content */],
337
private_metadata: JSON.stringify({ step: 1, data: {} }),
338
callback_id: "setup_workflow"
339
};
340
```
341
342
### Dynamic Content
343
344
Modal content can be updated using the `views.update` API method with the same view structure.
345
346
## App Home Patterns
347
348
App Home views provide a persistent interface for users:
349
350
### Dashboard Layout
351
352
```typescript
353
const dashboardHome: HomeView = {
354
type: "home",
355
blocks: [
356
{ type: "header", text: { type: "plain_text", text: "Dashboard" } },
357
{ type: "divider" },
358
{
359
type: "section",
360
text: { type: "mrkdwn", text: "*Recent Activity*" },
361
accessory: {
362
type: "button",
363
text: { type: "plain_text", text: "Refresh" },
364
action_id: "refresh_dashboard"
365
}
366
}
367
]
368
};
369
```
370
371
### Navigation Menu
372
373
```typescript
374
const navigationHome: HomeView = {
375
type: "home",
376
blocks: [
377
{
378
type: "actions",
379
elements: [
380
{
381
type: "button",
382
text: { type: "plain_text", text: "π Reports" },
383
action_id: "show_reports"
384
},
385
{
386
type: "button",
387
text: { type: "plain_text", text: "βοΈ Settings" },
388
action_id: "show_settings"
389
},
390
{
391
type: "button",
392
text: { type: "plain_text", text: "β Help" },
393
action_id: "show_help"
394
}
395
]
396
}
397
]
398
};
399
```