or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

commands-interactions.mdcore-clients.mddiscord-objects.mderror-handling.mdextensions.mdindex.mdui-components.mdutilities-helpers.md

ui-components.mddocs/

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.