0
# UI Components and Views
1
2
Interactive user interface elements including buttons, select menus, modals, and the view system for creating rich, interactive Discord bot interfaces. These components enable modern, engaging user experiences within Discord.
3
4
## Capabilities
5
6
### Views and Component Containers
7
8
Views act as containers for UI components and handle their lifecycle and interactions.
9
10
```python { .api }
11
class View:
12
"""
13
A container for UI components attached to messages.
14
"""
15
16
def __init__(
17
self,
18
*,
19
timeout: Optional[float] = 180.0,
20
disable_on_timeout: bool = False
21
) -> None:
22
"""
23
Create a view.
24
25
Parameters:
26
- timeout: float - Seconds before the view times out (None for no timeout)
27
- disable_on_timeout: bool - Whether to disable components on timeout
28
"""
29
30
@property
31
def timeout(self) -> Optional[float]:
32
"""The view's timeout in seconds."""
33
34
@property
35
def children(self) -> List[Item]:
36
"""List of child components."""
37
38
def add_item(self, item: Item) -> View:
39
"""Add a component to the view."""
40
41
def remove_item(self, item: Item) -> View:
42
"""Remove a component from the view."""
43
44
def clear_items(self) -> View:
45
"""Remove all components from the view."""
46
47
def get_item(self, custom_id: str) -> Optional[Item]:
48
"""Get a component by custom ID."""
49
50
def disable_all_items(self, *, exclusions: List[Item] = None) -> View:
51
"""
52
Disable all components in the view.
53
54
Parameters:
55
- exclusions: List[Item] - Components to exclude from disabling
56
"""
57
58
def enable_all_items(self, *, exclusions: List[Item] = None) -> View:
59
"""
60
Enable all components in the view.
61
62
Parameters:
63
- exclusions: List[Item] - Components to exclude from enabling
64
"""
65
66
def stop(self) -> None:
67
"""Stop the view and prevent further interactions."""
68
69
def is_finished(self) -> bool:
70
"""Check if the view has finished."""
71
72
def is_dispatching(self) -> bool:
73
"""Check if the view is currently handling interactions."""
74
75
def is_persistent(self) -> bool:
76
"""Check if the view is persistent (survives bot restarts)."""
77
78
async def wait(self) -> bool:
79
"""Wait until the view finishes."""
80
81
async def on_timeout(self) -> None:
82
"""Called when the view times out."""
83
84
async def on_error(
85
self,
86
error: Exception,
87
item: Item,
88
interaction: Interaction
89
) -> None:
90
"""
91
Called when an error occurs in a component callback.
92
93
Parameters:
94
- error: Exception - The error that occurred
95
- item: Item - The component that caused the error
96
- interaction: Interaction - The interaction that caused the error
97
"""
98
99
async def interaction_check(self, interaction: Interaction) -> bool:
100
"""
101
Check if an interaction should be processed.
102
103
Parameters:
104
- interaction: Interaction - The interaction to check
105
106
Returns:
107
bool - Whether the interaction should be processed
108
"""
109
110
class Item:
111
"""
112
Base class for all UI components.
113
"""
114
115
@property
116
def type(self) -> ComponentType:
117
"""The component type."""
118
119
@property
120
def custom_id(self) -> Optional[str]:
121
"""The component's custom ID."""
122
123
@property
124
def row(self) -> Optional[int]:
125
"""The component's row (0-4)."""
126
127
@property
128
def width(self) -> int:
129
"""The component's width (1-5 for buttons, 5 for others)."""
130
131
@property
132
def view(self) -> Optional[View]:
133
"""The view containing this component."""
134
135
def is_dispatching(self) -> bool:
136
"""Check if the component is handling an interaction."""
137
138
def is_persistent(self) -> bool:
139
"""Check if the component is persistent."""
140
141
class Component:
142
"""
143
Represents a Discord message component.
144
"""
145
146
@property
147
def type(self) -> ComponentType: ...
148
@property
149
def custom_id(self) -> Optional[str]: ...
150
151
@classmethod
152
def from_dict(cls, data: Dict[str, Any]) -> Component:
153
"""Create a component from raw data."""
154
155
def to_dict(self) -> Dict[str, Any]:
156
"""Convert the component to raw data."""
157
158
class ActionRow(Component):
159
"""
160
Represents an action row containing components.
161
"""
162
163
def __init__(self, *children: Item) -> None: ...
164
165
@property
166
def children(self) -> List[Item]: ...
167
168
def add_item(self, item: Item) -> ActionRow: ...
169
def append_item(self, item: Item) -> ActionRow: ...
170
def insert_item(self, index: int, item: Item) -> ActionRow: ...
171
def remove_item(self, item: Item) -> ActionRow: ...
172
```
173
174
### Buttons
175
176
Interactive button components that users can click to trigger actions.
177
178
```python { .api }
179
class Button(Item):
180
"""
181
Represents a button component.
182
"""
183
184
def __init__(
185
self,
186
*,
187
style: ButtonStyle = ButtonStyle.secondary,
188
label: Optional[str] = None,
189
disabled: bool = False,
190
custom_id: Optional[str] = None,
191
url: Optional[str] = None,
192
emoji: Optional[Union[str, Emoji, PartialEmoji]] = None,
193
row: Optional[int] = None
194
) -> None:
195
"""
196
Create a button.
197
198
Parameters:
199
- style: ButtonStyle - Visual style of the button
200
- label: str - Button text (required for non-emoji buttons)
201
- disabled: bool - Whether the button is disabled
202
- custom_id: str - Custom ID for identifying the button
203
- url: str - URL for link buttons (style must be link)
204
- emoji: Union[str, Emoji, PartialEmoji] - Button emoji
205
- row: int - Row to place the button (0-4)
206
"""
207
208
@property
209
def style(self) -> ButtonStyle:
210
"""The button's style."""
211
212
@property
213
def label(self) -> Optional[str]:
214
"""The button's label."""
215
216
@property
217
def disabled(self) -> bool:
218
"""Whether the button is disabled."""
219
220
@property
221
def url(self) -> Optional[str]:
222
"""The button's URL (for link buttons)."""
223
224
@property
225
def emoji(self) -> Optional[Union[str, Emoji, PartialEmoji]]:
226
"""The button's emoji."""
227
228
async def callback(self, interaction: Interaction) -> None:
229
"""Called when the button is clicked."""
230
231
def button(
232
*,
233
label: str = None,
234
style: ButtonStyle = ButtonStyle.secondary,
235
disabled: bool = False,
236
custom_id: str = None,
237
url: str = None,
238
emoji: Union[str, Emoji, PartialEmoji] = None,
239
row: int = None
240
) -> Callable:
241
"""
242
Decorator to create a button component.
243
244
Parameters:
245
- label: str - Button text
246
- style: ButtonStyle - Visual style
247
- disabled: bool - Whether disabled
248
- custom_id: str - Custom identifier
249
- url: str - URL for link buttons
250
- emoji: Union[str, Emoji, PartialEmoji] - Button emoji
251
- row: int - Button row (0-4)
252
"""
253
254
class ButtonStyle(Enum):
255
"""Button visual styles."""
256
primary = 1 # Blurple
257
secondary = 2 # Grey
258
success = 3 # Green
259
danger = 4 # Red
260
link = 5 # Grey, navigates to URL
261
262
# Aliases
263
blurple = 1
264
grey = 2
265
gray = 2
266
green = 3
267
red = 4
268
url = 5
269
```
270
271
### Select Menus
272
273
Dropdown menus for selecting from predefined options or Discord entities.
274
275
```python { .api }
276
class Select(Item):
277
"""
278
Base class for select menu components.
279
"""
280
281
def __init__(
282
self,
283
*,
284
custom_id: str = None,
285
placeholder: str = None,
286
min_values: int = 1,
287
max_values: int = 1,
288
disabled: bool = False,
289
row: int = None
290
) -> None:
291
"""
292
Create a select menu.
293
294
Parameters:
295
- custom_id: str - Custom identifier
296
- placeholder: str - Placeholder text when nothing is selected
297
- min_values: int - Minimum number of selections
298
- max_values: int - Maximum number of selections
299
- disabled: bool - Whether the select menu is disabled
300
- row: int - Row to place the select menu (0-4)
301
"""
302
303
@property
304
def placeholder(self) -> Optional[str]:
305
"""The select menu's placeholder text."""
306
307
@property
308
def min_values(self) -> int:
309
"""Minimum number of selections required."""
310
311
@property
312
def max_values(self) -> int:
313
"""Maximum number of selections allowed."""
314
315
@property
316
def disabled(self) -> bool:
317
"""Whether the select menu is disabled."""
318
319
@property
320
def values(self) -> List[str]:
321
"""The currently selected values."""
322
323
async def callback(self, interaction: Interaction) -> None:
324
"""Called when selections are made."""
325
326
class SelectMenu(Select):
327
"""
328
String-based select menu with custom options.
329
"""
330
331
def __init__(
332
self,
333
*,
334
options: List[SelectOption] = None,
335
**kwargs
336
) -> None:
337
"""
338
Create a string select menu.
339
340
Parameters:
341
- options: List[SelectOption] - Available options
342
"""
343
344
@property
345
def options(self) -> List[SelectOption]:
346
"""The select menu's options."""
347
348
def add_option(
349
self,
350
*,
351
label: str,
352
value: str = None,
353
description: str = None,
354
emoji: Union[str, Emoji, PartialEmoji] = None,
355
default: bool = False
356
) -> SelectMenu:
357
"""Add an option to the select menu."""
358
359
class SelectOption:
360
"""
361
Represents an option in a select menu.
362
"""
363
364
def __init__(
365
self,
366
*,
367
label: str,
368
value: str = None,
369
description: str = None,
370
emoji: Union[str, Emoji, PartialEmoji] = None,
371
default: bool = False
372
) -> None:
373
"""
374
Create a select option.
375
376
Parameters:
377
- label: str - Option display text
378
- value: str - Option value (defaults to label)
379
- description: str - Option description
380
- emoji: Union[str, Emoji, PartialEmoji] - Option emoji
381
- default: bool - Whether this option is selected by default
382
"""
383
384
@property
385
def label(self) -> str: ...
386
@property
387
def value(self) -> str: ...
388
@property
389
def description(self) -> Optional[str]: ...
390
@property
391
def emoji(self) -> Optional[Union[str, Emoji, PartialEmoji]]: ...
392
@property
393
def default(self) -> bool: ...
394
395
# Select Menu Decorators and Specialized Selects
396
def select(
397
*,
398
placeholder: str = None,
399
custom_id: str = None,
400
min_values: int = 1,
401
max_values: int = 1,
402
options: List[SelectOption] = None,
403
disabled: bool = False,
404
row: int = None
405
) -> Callable:
406
"""Decorator to create a string select menu."""
407
408
def string_select(
409
*,
410
placeholder: str = None,
411
custom_id: str = None,
412
min_values: int = 1,
413
max_values: int = 1,
414
options: List[SelectOption] = None,
415
disabled: bool = False,
416
row: int = None
417
) -> Callable:
418
"""Decorator to create a string select menu."""
419
420
def user_select(
421
*,
422
placeholder: str = None,
423
custom_id: str = None,
424
min_values: int = 1,
425
max_values: int = 1,
426
disabled: bool = False,
427
row: int = None
428
) -> Callable:
429
"""
430
Decorator to create a user select menu.
431
432
Users can select from guild members and the bot user.
433
"""
434
435
def role_select(
436
*,
437
placeholder: str = None,
438
custom_id: str = None,
439
min_values: int = 1,
440
max_values: int = 1,
441
disabled: bool = False,
442
row: int = None
443
) -> Callable:
444
"""
445
Decorator to create a role select menu.
446
447
Users can select from guild roles.
448
"""
449
450
def mentionable_select(
451
*,
452
placeholder: str = None,
453
custom_id: str = None,
454
min_values: int = 1,
455
max_values: int = 1,
456
disabled: bool = False,
457
row: int = None
458
) -> Callable:
459
"""
460
Decorator to create a mentionable select menu.
461
462
Users can select from users and roles.
463
"""
464
465
def channel_select(
466
*,
467
placeholder: str = None,
468
custom_id: str = None,
469
min_values: int = 1,
470
max_values: int = 1,
471
channel_types: List[ChannelType] = None,
472
disabled: bool = False,
473
row: int = None
474
) -> Callable:
475
"""
476
Decorator to create a channel select menu.
477
478
Parameters:
479
- channel_types: List[ChannelType] - Types of channels to include
480
"""
481
```
482
483
### Modals and Text Input
484
485
Modal dialogs for collecting text input from users.
486
487
```python { .api }
488
class Modal:
489
"""
490
Represents a modal dialog for collecting user input.
491
"""
492
493
def __init__(
494
self,
495
*children: InputText,
496
title: str,
497
custom_id: str = None,
498
timeout: Optional[float] = None
499
) -> None:
500
"""
501
Create a modal.
502
503
Parameters:
504
*children: InputText - Text input components
505
- title: str - Modal title
506
- custom_id: str - Custom identifier
507
- timeout: float - Timeout in seconds
508
"""
509
510
@property
511
def title(self) -> str:
512
"""The modal's title."""
513
514
@property
515
def custom_id(self) -> str:
516
"""The modal's custom ID."""
517
518
@property
519
def timeout(self) -> Optional[float]:
520
"""The modal's timeout."""
521
522
@property
523
def children(self) -> List[InputText]:
524
"""The modal's input components."""
525
526
def add_item(self, item: InputText) -> Modal:
527
"""Add an input component to the modal."""
528
529
def remove_item(self, item: InputText) -> Modal:
530
"""Remove an input component from the modal."""
531
532
def clear_items(self) -> Modal:
533
"""Remove all input components."""
534
535
def stop(self) -> None:
536
"""Stop the modal."""
537
538
async def callback(self, interaction: Interaction) -> None:
539
"""
540
Called when the modal is submitted.
541
542
Parameters:
543
- interaction: Interaction - The modal submit interaction
544
"""
545
546
async def on_timeout(self) -> None:
547
"""Called when the modal times out."""
548
549
async def on_error(self, error: Exception, interaction: Interaction) -> None:
550
"""
551
Called when an error occurs.
552
553
Parameters:
554
- error: Exception - The error that occurred
555
- interaction: Interaction - The interaction that caused the error
556
"""
557
558
class InputText(Item):
559
"""
560
Represents a text input field in a modal.
561
"""
562
563
def __init__(
564
self,
565
*,
566
label: str,
567
style: InputTextStyle = InputTextStyle.short,
568
placeholder: str = None,
569
custom_id: str = None,
570
value: str = None,
571
required: bool = True,
572
min_length: int = None,
573
max_length: int = None,
574
row: int = None
575
) -> None:
576
"""
577
Create a text input.
578
579
Parameters:
580
- label: str - Input label
581
- style: InputTextStyle - Input style (short or long)
582
- placeholder: str - Placeholder text
583
- custom_id: str - Custom identifier
584
- value: str - Pre-filled value
585
- required: bool - Whether input is required
586
- min_length: int - Minimum input length
587
- max_length: int - Maximum input length
588
- row: int - Row position (0-4)
589
"""
590
591
@property
592
def label(self) -> str:
593
"""The input's label."""
594
595
@property
596
def style(self) -> InputTextStyle:
597
"""The input's style."""
598
599
@property
600
def placeholder(self) -> Optional[str]:
601
"""The input's placeholder text."""
602
603
@property
604
def value(self) -> Optional[str]:
605
"""The input's current value."""
606
607
@property
608
def default(self) -> Optional[str]:
609
"""The input's default value."""
610
611
@property
612
def required(self) -> bool:
613
"""Whether the input is required."""
614
615
@property
616
def min_length(self) -> Optional[int]:
617
"""Minimum input length."""
618
619
@property
620
def max_length(self) -> Optional[int]:
621
"""Maximum input length."""
622
623
class InputTextStyle(Enum):
624
"""Text input styles."""
625
short = 1 # Single line input
626
long = 2 # Multi-line input (paragraph)
627
628
# Aliases
629
paragraph = 2
630
```
631
632
### Modal Store for Persistent Modals
633
634
Storage system for handling modals across bot restarts.
635
636
```python { .api }
637
class ModalStore:
638
"""
639
Stores modal callbacks for persistent modals.
640
"""
641
642
def __init__(self) -> None: ...
643
644
def add_modal(self, modal: Modal, *, user_id: int = None) -> None:
645
"""
646
Add a modal to the store.
647
648
Parameters:
649
- modal: Modal - The modal to store
650
- user_id: int - User ID for user-specific modals
651
"""
652
653
def remove_modal(self, custom_id: str, *, user_id: int = None) -> Optional[Modal]:
654
"""
655
Remove a modal from the store.
656
657
Parameters:
658
- custom_id: str - Modal custom ID
659
- user_id: int - User ID for user-specific modals
660
"""
661
662
def get_modal(self, custom_id: str, *, user_id: int = None) -> Optional[Modal]:
663
"""
664
Get a modal from the store.
665
666
Parameters:
667
- custom_id: str - Modal custom ID
668
- user_id: int - User ID for user-specific modals
669
"""
670
671
def clear(self) -> None:
672
"""Clear all stored modals."""
673
```
674
675
### Component Types and Enumerations
676
677
Enumerations for component identification and configuration.
678
679
```python { .api }
680
class ComponentType(Enum):
681
"""Message component types."""
682
action_row = 1
683
button = 2
684
select = 3
685
text_input = 4
686
user_select = 5
687
role_select = 6
688
mentionable_select = 7
689
channel_select = 8
690
691
# Aliases
692
string_select = 3
693
```
694
695
### Usage Examples
696
697
Example implementations showing common UI patterns:
698
699
```python
700
# Example: Confirmation Dialog
701
class ConfirmView(discord.ui.View):
702
def __init__(self, *, timeout=180):
703
super().__init__(timeout=timeout)
704
self.value = None
705
706
@discord.ui.button(label='Confirm', style=discord.ButtonStyle.green)
707
async def confirm(self, button: discord.ui.Button, interaction: discord.Interaction):
708
self.value = True
709
self.stop()
710
711
@discord.ui.button(label='Cancel', style=discord.ButtonStyle.grey)
712
async def cancel(self, button: discord.ui.Button, interaction: discord.Interaction):
713
self.value = False
714
self.stop()
715
716
# Example: Dropdown Selection
717
class DropdownView(discord.ui.View):
718
@discord.ui.select(
719
placeholder="Choose an option...",
720
min_values=1,
721
max_values=1,
722
options=[
723
discord.SelectOption(label="Option 1", description="First option"),
724
discord.SelectOption(label="Option 2", description="Second option"),
725
discord.SelectOption(label="Option 3", description="Third option")
726
]
727
)
728
async def select_callback(self, select, interaction):
729
await interaction.response.send_message(f"You chose {select.values[0]}")
730
731
# Example: Modal Form
732
class FeedbackModal(discord.ui.Modal):
733
def __init__(self, *args, **kwargs):
734
super().__init__(
735
discord.ui.InputText(
736
label="Subject",
737
placeholder="What is this about?"
738
),
739
discord.ui.InputText(
740
label="Details",
741
style=discord.InputTextStyle.long,
742
placeholder="Please provide more details..."
743
),
744
title="Feedback Form",
745
*args, **kwargs
746
)
747
748
async def callback(self, interaction: discord.Interaction):
749
embed = discord.Embed(
750
title="Feedback Received",
751
description=f"**Subject:** {self.children[0].value}\n**Details:** {self.children[1].value}",
752
color=discord.Color.green()
753
)
754
await interaction.response.send_message(embed=embed, ephemeral=True)
755
```
756
757
The UI components system enables rich, interactive Discord applications with modern user interfaces that provide engaging and intuitive user experiences through buttons, select menus, modals, and sophisticated view management.