Field types overview
Spraxium modals support 11 field types, each declared through a property-level decorator on your @ModalComponent class. Text inputs and selects are the most common, but the system also includes radio groups, checkboxes, file uploads, and read-only text displays. Every field decorator accepts a configuration object with properties specific to the field type, plus shared properties like label and required.
The field order in the rendered modal matches the declaration order of the decorated properties in the class. Discord modals have a maximum of 5 action rows, and each field occupies one row. This limit means a single modal can contain at most 5 fields, though dynamic and conditional fields can alter what appears for each user.
| Decorator | Field type | Accepts choices | Notes |
|---|---|---|---|
| @ModalInput | Text input | No | Short or paragraph style. Supports minLength, maxLength, placeholder. |
| @ModalSelect | String select | Yes | Dropdown with static or dynamic options. Supports minValues, maxValues. |
| @ModalUserSelect | User select | No | Server member picker. Default values supported. |
| @ModalRoleSelect | Role select | No | Server role picker. Default values supported. |
| @ModalMentionableSelect | Mentionable select | No | Picks users or roles. Combines both entity types in one dropdown. |
| @ModalChannelSelect | Channel select | No | Channel picker. Filter by channelTypes array. |
| @ModalRadioGroup | Radio group | Yes | Single-selection radio buttons. Exactly one option must be selected. |
| @ModalCheckboxGroup | Checkbox group | Yes | Multi-selection checkboxes. Supports minValues, maxValues. |
| @ModalCheckbox | Single checkbox | No | Boolean toggle. Returns |
| @ModalFileUpload | File upload | No | Attachment field. Access the uploaded file through the interaction. |
| @ModalTextDisplay | Read-only text | No | Static text shown in the modal. Not submitted as a value. |
Text inputs
The @ModalInput decorator creates a text input field. The style property controls whether the field renders as a single-line (short) or multi-line (paragraph) input. Short fields are ideal for names, subjects, and brief values. Paragraph fields suit descriptions, messages, and longer content.
import { ModalComponent, ModalInput } from '@spraxium/components';
@ModalComponent({ id: 'report-modal', title: 'Submit Report' })
export class ReportModal {
@ModalInput({
label: 'Title',
placeholder: 'A short title for the report',
required: true,
minLength: 5,
maxLength: 100,
style: 'short',
})
title!: string;
@ModalInput({
label: 'Description',
placeholder: 'Describe the issue in detail...',
required: true,
minLength: 20,
maxLength: 4000,
style: 'paragraph',
})
description!: string;
@ModalInput({
label: 'Reproduction Steps',
placeholder: 'Optional steps to reproduce',
required: false,
style: 'paragraph',
value: "1. \n2. \n3. ",
})
steps!: string;
}String selects with choices
The @ModalSelect decorator creates a dropdown select menu inside the modal. Define the available options using the @ModalChoice stackable decorator on the same property. Each choice has a label (displayed to the user), value (sent on submission), and an optional description.
import { ModalComponent, ModalSelect, ModalChoice } from '@spraxium/components';
@ModalComponent({ id: 'ticket-modal', title: 'Create Ticket' })
export class TicketModal {
@ModalSelect({
label: 'Category',
placeholder: 'Select a ticket category',
required: true,
})
@ModalChoice({
label: 'Bug Report',
value: 'bug',
description: 'Something is broken',
})
@ModalChoice({
label: 'Feature Request',
value: 'feature',
description: 'Suggest an improvement',
})
@ModalChoice({
label: 'General Question',
value: 'question',
description: 'Ask a question',
})
category!: string;
@ModalInput({
label: 'Details',
style: 'paragraph',
required: true,
})
details!: string;
}Entity selects
Entity select decorators let users pick server members, roles, channels, or mentionable entities directly from the modal. These fields use Discord's native entity pickers, so they show avatars, role colors, and channel icons. No @ModalChoice decorators are needed because the options are populated from the server.
import { ModalComponent, ModalUserSelect } from '@spraxium/components';
@ModalComponent({ id: 'assign-modal', title: 'Assign User' })
export class AssignModal {
@ModalUserSelect({
label: 'Assignee',
placeholder: 'Pick a team member',
required: true,
})
assignee!: string;
}Radio groups and checkboxes
Radio groups present mutually exclusive options where the user must pick exactly one. Checkbox groups allow multiple selections. A single @ModalCheckbox renders as a boolean toggle. All choice-based fields use @ModalOption (an alias for @ModalChoice) to define their options.
import { ModalComponent, ModalRadioGroup, ModalOption } from '@spraxium/components';
@ModalComponent({ id: 'priority-modal', title: 'Set Priority' })
export class PriorityModal {
@ModalRadioGroup({ label: 'Priority Level' })
@ModalOption({ label: 'Low', value: 'low' })
@ModalOption({ label: 'Medium', value: 'medium' })
@ModalOption({ label: 'High', value: 'high' })
@ModalOption({ label: 'Critical', value: 'critical' })
priority!: string;
}File uploads and text displays
The @ModalFileUpload decorator adds an attachment field to the modal. The @ModalTextDisplay decorator adds read-only static text that is not submitted as a field value. Text displays are useful for showing instructions, warnings, or context information within the modal form itself.
import {
ModalComponent,
ModalTextDisplay,
ModalFileUpload,
ModalInput,
} from '@spraxium/components';
@ModalTextDisplay({
content:
'Please upload a screenshot or log file as evidence. Accepted formats: PNG, JPG, TXT.',
})
@ModalComponent({ id: 'evidence-modal', title: 'Upload Evidence' })
export class UploadEvidenceModal {
@ModalFileUpload({
label: 'Evidence File',
required: true,
})
file!: string;
@ModalInput({
label: 'Additional Notes',
style: 'paragraph',
required: false,
placeholder: 'Any extra context about the evidence...',
})
notes!: string;
}Modal namespace helpers
The Modal namespace provides factory functions for creating field definitions programmatically instead of using decorators. This is primarily used with dynamic fields (covered in the dynamics page), but can also be useful when building modal schemas in utility functions or shared libraries.
| Helper | Returns | Equivalent decorator |
|---|---|---|
| Modal.field.text(config) | Text input field def | @ModalInput |
| Modal.field.stringSelect(config) | String select field def | @ModalSelect |
| Modal.field.userSelect(config) | User select field def | @ModalUserSelect |
| Modal.field.roleSelect(config) | Role select field def | @ModalRoleSelect |
| Modal.field.mentionableSelect(config) | Mentionable select field def | @ModalMentionableSelect |
| Modal.field.channelSelect(config) | Channel select field def | @ModalChannelSelect |
| Modal.field.radioGroup(config) | Radio group field def | @ModalRadioGroup |
| Modal.field.checkboxGroup(config) | Checkbox group field def | @ModalCheckboxGroup |
| Modal.field.checkbox(config) | Single checkbox field def | @ModalCheckbox |
| Modal.field.fileUpload(config) | File upload field def | @ModalFileUpload |
| Modal.field.textDisplay(config) | Text display field def | @ModalTextDisplay |
| Modal.choice(config) | Choice definition | @ModalChoice / @ModalOption |
| Modal.when(predicate) | Conditional wrapper | @ModalWhen |
import { Modal } from '@spraxium/components';
export function createReasonField(required = true) {
return Modal.field.text({
id: 'reason',
label: 'Reason',
placeholder: 'Provide a reason...',
style: 'paragraph',
required,
minLength: 10,
});
}
export function createPriorityChoices() {
return [
Modal.choice({ label: 'Low', value: 'low' }),
Modal.choice({ label: 'Medium', value: 'medium' }),
Modal.choice({ label: 'High', value: 'high' }),
];
}