Spraxium logoSpraxium

Modal Fields

Declare modal fields with property decorators for text inputs, selects, radios, checkboxes, and more. Learn all 11 field types, choice decorators, display fields, and the Modal namespace helpers.

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.

DecoratorField typeAccepts choicesNotes
@ModalInputText inputNo

Short or paragraph style. Supports minLength, maxLength, placeholder.

@ModalSelectString selectYes

Dropdown with static or dynamic options. Supports minValues, maxValues.

@ModalUserSelectUser selectNoServer member picker. Default values supported.
@ModalRoleSelectRole selectNoServer role picker. Default values supported.
@ModalMentionableSelectMentionable selectNo

Picks users or roles. Combines both entity types in one dropdown.

@ModalChannelSelectChannel selectNoChannel picker. Filter by channelTypes array.
@ModalRadioGroupRadio groupYes

Single-selection radio buttons. Exactly one option must be selected.

@ModalCheckboxGroupCheckbox groupYes

Multi-selection checkboxes. Supports minValues, maxValues.

@ModalCheckboxSingle checkboxNo

Boolean toggle. Returns true or false as string.

@ModalFileUploadFile uploadNo

Attachment field. Access the uploaded file through the interaction.

@ModalTextDisplayRead-only textNo

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.

src/components/report.modal.ts
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.

src/components/category-select.modal.ts
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.

src/components/upload-evidence.modal.ts
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;
}

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.

HelperReturnsEquivalent 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
src/utils/modal-helpers.ts
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' }),
  ];
}