Seyfert v4.2.0: Discord's New Modal Components
Radio groups, checkbox groups, checkboxes, resolved data in modals, file support in forum threads, and select menu improvements.
February 13, 2026
The Big One: New Modal Components
Discord just shipped three new component types for modals, and Seyfert v4.2.0 has full support from day one. Build richer forms without workaround hacks.
Radio Groups
Single-choice selection, built for modals. Give users 2-10 options and get back the selected value.
import { RadioGroup, RadioGroupOption, Label } from 'seyfert';
const label = new Label()
.setLabel('Pick your favorite language')
.setComponent(
new RadioGroup()
.setCustomId('language')
.addOptions(
new RadioGroupOption().setLabel('TypeScript').setValue('ts'),
new RadioGroupOption().setLabel('Rust').setValue('rs'),
new RadioGroupOption().setLabel('Go').setValue('go'),
)
);Read the value back in your modal handler:
async run(ctx: ModalContext) {
const language = ctx.interaction.getRadioValues('language', true);
// "ts" | "rs" | "go"
}Checkbox Groups
Multi-selection with min/max constraints. Same builder pattern, multiple values returned.
import { CheckboxGroup, CheckboxGroupOption, Label } from 'seyfert';
const label = new Label()
.setLabel('Select your roles')
.setComponent(
new CheckboxGroup()
.setCustomId('roles')
.setSelectionLimit({ min: 1, max: 3 })
.addOptions(
new CheckboxGroupOption({ label: 'Developer', value: 'dev' }),
new CheckboxGroupOption({ label: 'Designer', value: 'design' }),
new CheckboxGroupOption({ label: 'Moderator', value: 'mod' }),
)
);async run(ctx: ModalContext) {
const roles = ctx.interaction.getCheckboxValues('roles', true);
// ["dev", "mod"]
}Standalone Checkboxes
A simple yes/no toggle. Returns a boolean.
import { Checkbox, Label } from 'seyfert';
const label = new Label()
.setLabel('Accept terms of service')
.setComponent(
new Checkbox()
.setCustomId('tos')
.setDefault(false)
);async run(ctx: ModalContext) {
const accepted = ctx.interaction.getCheckbox('tos', true);
// true | false
}Resolved Data in Modal Submissions
Modals now support select menus for channels, roles, users, and mentionables. Seyfert provides dedicated accessors that return fully resolved structures:
async run(ctx: ModalContext) {
const channels = ctx.interaction.getChannels('channel-select', true);
const roles = ctx.interaction.getRoles('role-select', true);
const users = ctx.interaction.getUsers('user-select', true);
const mentionables = ctx.interaction.getMentionables('mention-select', true);
}Each method accepts a required flag. When true, it throws if the component isn't found. When false, it returns void instead.
Select Menu required Property
Select menus now support a required property for modal usage. Discord defaults this to true -- set it to false if you want optional selections.
new StringSelectMenu()
.setCustomId('optional-pick')
.setRequired(false)
.addOptions(/* ... */);File Attachments in Forum Threads
Creating forum threads with file attachments previously required manual workarounds. The thread creation API now properly handles files alongside message content.
const thread = await channel.thread({
name: 'Bug Report',
message: {
content: 'See attached screenshot',
},
files: [{ name: 'screenshot.png', data: buffer }],
});The new ThreadOnlyCreateBodyRequest type enforces that at least one of message or files is provided, so you can't accidentally create an empty forum post.
Bug Fixes
Guild Command Registration
Commands with an empty guildId array were incorrectly treated as guild commands instead of global commands. Fixed by checking guildId.length > 0 rather than just truthiness.
Modal getInputValue / getFiles
Both methods now correctly use the new label-based component structure introduced by Discord's modal changes. getInputValue filters by TextInput and StringSelect types, and getFiles properly resolves file upload components.
Internal Improvements
- Enforced
useImportTypeacross the codebase via Biome, converting value imports to type-only imports where applicable. - Component type interfaces (
APISectionComponent,APIContainerComponent, etc.) now properly extendAPIBaseComponentinstead of definingtypeinline. - New utility type
RequireAtLeastOne<T, Keys>for enforcing that at least one property in a set is provided.
Upgrade
pnpm install [email protected]Discord keeps expanding what modals can do. Seyfert v4.2.0 makes sure you can use all of it without friction.
Seyfert v4.1.0: Polishing the Details
Better context checks, invite management, role insights, and the cleanup you didn't know you needed.
Seyfert v4.3.0: The One Where Everything Gets Smarter
Guild message search, shard lifecycle hooks, permission overhaul, zombie connection slayer, and channel overwrites done right.