Confirmation modal
Construct a view with an input and submit button. Opening it requires a genuine interaction trigger ID; processing the submission belongs to your application.
Output
Local preview of the selected language’s tested example. Slack client appearance may differ; controls here do not send requests.
Confirm deletion
⚠️ This will permanently delete production.
Serialized output
{
"type": "modal",
"blocks": [
{
"type": "section",
"block_id": "<generated-block-id>",
"text": {
"type": "mrkdwn",
"text": ":warning: This will permanently delete *production*."
}
},
{
"type": "input",
"block_id": "confirmation",
"label": {
"type": "plain_text",
"text": "Type the name to confirm"
},
"element": {
"type": "plain_text_input",
"action_id": "confirmation_text",
"placeholder": {
"type": "plain_text",
"text": "production"
}
}
}
],
"private_metadata": "production",
"callback_id": "confirm_delete",
"title": {
"type": "plain_text",
"text": "Confirm deletion"
},
"close": {
"type": "plain_text",
"text": "Cancel"
},
"submit": {
"type": "plain_text",
"text": "Delete"
}
}
Code
Pass the constructed modal to views.open with an interaction trigger ID. The example only constructs the view; it makes no Slack request.
from slackblocks import (
InputBlock,
Modal,
PlainTextInput,
SectionBlock,
)
def confirmation_modal(target: str) -> Modal:
modal = Modal(
title="Confirm deletion",
submit="Delete",
close="Cancel",
callback_id="confirm_delete",
private_metadata=target, # round-tripped back to your handler on submit
blocks=[
SectionBlock(f":warning: This will permanently delete *{target}*."),
InputBlock(
label="Type the name to confirm",
element=PlainTextInput(
action_id="confirmation_text",
placeholder=target,
),
block_id="confirmation",
),
],
)
return modal
print(confirmation_modal("production").json())
import * as S from "@nicklambourne/slackblocks";
const view = S.Modal().title("Confirm deployment").submit("Deploy").callbackId("deploy").blocks(
S.InputBlock().label("Reason").blockId("reason").element(S.PlainTextInput().actionId("reason_input")),
).build();
console.log(JSON.stringify(view));
package main
import (
"encoding/json"
s "github.com/nicklambourne/slackblocks/go/v3"
"os"
)
func main() {
value, err := s.NewModal().Title("Confirm deployment").Submit("Deploy").CallbackID("deploy").Blocks(
s.NewInputBlock().Label("Reason").BlockID("reason").Element(s.NewPlainTextInput().ActionID("reason_input")),
).Build()
if err != nil {
panic(err)
}
if err := json.NewEncoder(os.Stdout).Encode(value); err != nil {
panic(err)
}
}
import io.github.nicklambourne.slackblocks.*;
import io.github.nicklambourne.slackblocks.block.*;
import io.github.nicklambourne.slackblocks.component.*;
import io.github.nicklambourne.slackblocks.element.*;
import io.github.nicklambourne.slackblocks.object.*;
import io.github.nicklambourne.slackblocks.payload.*;
import java.util.List;
import java.util.Map;
public final class Recipe {
public static void main(String[] args) throws Exception {
var value = ModalView.builder().title("Confirm deployment").submit("Deploy").callbackId("deploy").blocks(
InputBlock.builder().label("Reason").blockId("reason").element(
PlainTextInputElement.builder().actionId("reason_input").build()).build()).build();
System.out.println(value.toJson());
}
}
using System;
using System.Collections.Generic;
using Slackblocks;
using Slackblocks.Blocks;
using Slackblocks.Components;
using Slackblocks.Elements;
using Slackblocks.Objects;
using Slackblocks.Payloads;
var value = new ModalView("Confirm deployment", submit: "Deploy", callbackId: "deploy", blocks: [
new InputBlock("Reason", new PlainTextInputElement(actionId: "reason_input"), blockId: "reason"),
]);
Console.WriteLine(value.ToJson());
require "slackblocks"
include Slackblocks
value = ModalView.new(title: "Confirm deployment", submit: "Deploy", callback_id: "deploy", blocks: [
InputBlock.new(label: "Reason", block_id: "reason", element: PlainTextInputElement.new(action_id: "reason_input"))
])
puts value.to_json
use slackblocks::*;
fn main() -> Result<(), Box<dyn std::error::Error>> {
let modal = ModalView::builder()
.title("Approval")
.submit("Approve")
.close("Cancel")
.block(
InputBlock::builder()
.label("Reason")
.element(
PlainTextInputElement::builder()
.action_id("reason")
.build()?,
)
.build()?,
)
.build()?;
println!("{}", serde_json::to_string(&modal)?);
Ok(())
}
Input blocks require a modal submit label. Put this view in a views.open
request alongside the interaction's trigger ID.
<?php
declare(strict_types=1);
require 'vendor/autoload.php';
use Slackblocks as S;
$view = new S\ModalView(title: 'Confirm deployment', submit: 'Deploy', callbackId: 'deploy', blocks: [
new S\InputBlock(label: 'Reason', blockId: 'reason', element: new S\PlainTextInputElement(actionId: 'reason_input')),
]);
echo $view->toJson();
alias Slackblocks.{Blocks.Input, Elements.PlainTextInput, Views.Modal}
Modal.new!(title: "Confirm deployment", submit: "Deploy", callback_id: "deploy", blocks: [
Input.new!(label: "Reason", block_id: "reason", element: PlainTextInput.new!(action_id: "reason_input"))
]) |> Slackblocks.to_map!()
{-# LANGUAGE OverloadedStrings #-}
import Data.Aeson (encode)
import qualified Data.Map.Strict as Map
import Slackblocks
example = do
title <- buildPlainText (plainText "Confirm deployment")
submit <- buildPlainText (plainText "Deploy")
label <- buildPlainText (plainText "Reason")
field <- buildPlainTextInputElement (plainTextInputElement {plainTextInputElementActionId = Just "reason_input"})
input <- buildInputBlock ((inputBlock label (plainTextInputElementAsInputElement field)) {inputBlockBlockId = Just "reason"})
buildModalView ((modalView title [inputBlockAsBlock input]) {modalViewSubmit = Just submit, modalViewCallbackId = Just "deploy"})