Modals#
With the release of miru v2.0.0, modals are now available to use. They function in a very similar way to views, with a few notable exceptions, namely:
-
Modals are sent using builder objects.
-
Modal items do not have individual callbacks, instead the entire modal has one singular callback.
-
Modals only accept
ModalItem
s (currently this only includesTextInput
), and passModalContext
when the callback is triggered.
Note
Please note that modals can only be sent as an initial response to an interaction.
Let's create our first modal:
class MyModal(miru.Modal, title="Example Title"):
name = miru.TextInput(
label="Name",
placeholder="Type your name!",
required=True
)
bio = miru.TextInput(
label="Biography",
value="Pre-filled content!",
style=hikari.TextInputStyle.PARAGRAPH
)
# The callback function is called after the user hits 'Submit'
async def callback(self, ctx: miru.ModalContext) -> None:
# You can also access the values using ctx.values,
# Modal.values, or use ctx.get_value_by_id()
await ctx.respond(
f"Your name: `{self.name.value}`\nYour bio: ```{self.bio.value}```"
)
There is also an alternative way to add items to a modal, through the Modal.add_item()
method, similarly to views.
Warning
Please be careful when naming your modal item class variables. They cannot shadow existing modal properties such as title or custom_id.
Now, we will generate an interaction through the use of a button so we can send the user our modal:
class ModalView(miru.View):
# Create a new button that will invoke our modal
@miru.button(label="Click me!", style=hikari.ButtonStyle.PRIMARY)
async def modal_button(self, ctx: miru.ViewContext, button: miru.Button) -> None:
modal = MyModal()
await ctx.respond_with_modal(modal)
Combining the above code with the modal we created earlier, you should now have a basic working example where the user can click the button, get prompted with a modal, and then submit their input.
If you want to use modals in slash commands, you need to turn it into a builder, then send it as a response to the relevant interaction:
@bot.listen()
async def handle_commands(event: hikari.InteractionCreateEvent) -> None:
# Ignore other types of interactions
if not isinstance(event.interaction, hikari.CommandInteraction):
return
modal = MyModal()
builder = modal.build_response(client)
# Send the modal as a response to the interaction
await builder.create_modal_response(event.interaction)
client.start_modal(modal)
@crescent_client.include
@crescent.command("name", "description")
class SomeSlashCommand:
async def callback(self, ctx: crescent.Context) -> None:
modal = MyModal()
builder = modal.build_response(client)
# crescent has a built-in way to respond with a builder
await ctx.respond_with_builder(builder)
client.start_modal(modal)
@lightbulb_bot.command()
@lightbulb.command("name", "description", auto_defer=False)
@lightbulb.implements(lightbulb.SlashCommand)
async def some_slash_command(ctx: lightbulb.SlashContext) -> None:
modal = MyModal()
builder = modal.build_response(client)
await builder.create_modal_response(ctx.interaction)
client.start_modal(modal)
For more information on modals, please see the Modal
API reference.
Warning
A modal must be sent as the initial response to an interaction. You cannot defer before sending a modal.