slack-block-kit について
slack-block-kit は、Slack のインターフェースを開発する人向けの Block Kit リファレンススキルです。メッセージ、モーダル、Home タブの JSON 構造を、レイアウトブロックから入力要素まで解説します。
主な機能
- 01Block Kit ブロックのリファレンス
- 02インタラクティブ要素とメニュー
- 03コンポジションオブジェクトとテキスト
- 04メッセージ、モーダル、Home タブの各サーフェス
活用シーン
- 01Slack メッセージレイアウトの作成
- 02モーダルフォームとワークフローの作成
- 03Home タブへのインタラクティブコントロールの追加
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ freightcognition/ linehaulai-claude-marketplace --skill slack-block-kitインストール後、Claude Code で/slack-block-kitを入力して読み込まれたか確認します。
詳細
Slack Block Kit
Block Kit を使用して Slack UI を構築するための専門ガイドです。
概要
Block Kit は、リッチでインタラクティブなメッセージ、モーダル、ホームタブを作成するための Slack の UI フレームワークです。JSON ベースの構造を使用し、次の 3 つの主要コンポーネントで構成されています。
- ブロック:レイアウト用のコンテナー(Section、Actions、Input、Header など)
- エレメント:インタラクティブなコンポーネント(ボタン、セレクト、日付ピッカー)
- コンポジションオブジェクト:テキスト、オプション、確認
サーフェス
Block Kit は次の 3 つのサーフェスで動作します。
| サーフェス | ブロックの最大数 | 用途 |
|---|---|---|
| メッセージ | 50 | 通知、ボットの応答、チャンネルへの投稿 |
| モーダル | 100 | フォーム、確認、複数ステップのワークフロー |
| ホームタブ | 100 | アプリのダッシュボード、ユーザーごとのコンテンツ |
クイックスタート
シンプルなメッセージ
{
"blocks": [
{
"type": "header",
"text": {
"type": "plain_text",
"text": "New Order Received"
}
},
{
"type": "section",
"fields": [
{
"type": "mrkdwn",
"text": "*Order ID:*\n#12345"
},
{
"type": "mrkdwn",
"text": "*Customer:*\nJohn Doe"
}
]
},
{
"type": "actions",
"elements": [
{
"type": "button",
"text": {
"type": "plain_text",
"text": "View Order"
},
"style": "primary",
"action_id": "view_order",
"value": "12345"
}
]
}
]
}
slack-block-builder を使用する場合(JavaScript)
import { Message, Blocks, Elements } from 'slack-block-builder';
const orderNotification = ({ orderId, customer, channel }) => {
return Message({ channel, text: 'New Order Received' })
.blocks(
Blocks.Header({ text: 'New Order Received' }),
Blocks.Section()
.fields([
`*Order ID:*\n#${orderId}`,
`*Customer:*\n${customer}`
]),
Blocks.Actions()
.elements(
Elements.Button({ text: 'View Order', actionId: 'view_order' })
.primary()
.value(orderId)
)
)
.buildToObject();
};
ブロックリファレンス
Header ブロック
タイトル用の大きなテキストを表示します。
{
"type": "header",
"text": {
"type": "plain_text",
"text": "Budget Performance",
"emoji": true
}
}
フィールド:
type(必須):常に"header"text(必須):plain_text オブジェクト。最大 150 文字block_id(任意):一意の識別子。最大 255 文字
**サーフェス:**メッセージ、モーダル、ホームタブ
Section ブロック
テキストやアクセサリーに使用できる、最も汎用性の高いブロックです。
{
"type": "section",
"text": {
"type": "mrkdwn",
"text": "*Project Update*\nThe deployment is complete."
},
"accessory": {
"type": "button",
"text": {
"type": "plain_text",
"text": "View Details"
},
"action_id": "view_details"
}
}
フィールド付き(2 列レイアウト):
{
"type": "section",
"fields": [
{
"type": "mrkdwn",
"text": "*Status:*\nApproved"
},
{
"type": "mrkdwn",
"text": "*Created:*\nDec 15, 2025"
},
{
"type": "mrkdwn",
"text": "*Priority:*\nHigh"
},
{
"type": "mrkdwn",
"text": "*Assignee:*\n<@U123ABC>"
}
]
}
フィールド:
type(必須):常に"section"text(任意):テキストオブジェクト(mrkdwn または plain_text)。最大 3000 文字fields(任意):テキストオブジェクトの配列(最大 10 個)。各要素は最大 2000 文字accessory(任意):インタラクティブなエレメント 1 個block_id(任意):一意の識別子expand(任意):ブール値。デフォルトでテキストを展開するかどうか
**サーフェス:**メッセージ、モーダル、ホームタブ
Actions ブロック
複数のインタラクティブなエレメントを含みます。
{
"type": "actions",
"block_id": "approval_actions",
"elements": [
{
"type": "button",
"text": {
"type": "plain_text",
"text": "Approve"
},
"style": "primary",
"action_id": "approve_request",
"value": "approved"
},
{
"type": "button",
"text": {
"type": "plain_text",
"text": "Reject"
},
"style": "danger",
"action_id": "reject_request",
"value": "rejected"
}
]
}
フィールド:
type(必須):常に"actions"elements(必須):インタラクティブなエレメントの配列(最大 25 個)block_id(任意):一意の識別子
**サーフェス:**メッセージ、モーダル、ホームタブ
Input ブロック
ユーザー入力を収集します(主にモーダルとホームタブで使用します)。
{
"type": "input",
"block_id": "description_input",
"label": {
"type": "plain_text",
"text": "Description"
},
"element": {
"type": "plain_text_input",
"action_id": "description_value",
"multiline": true,
"placeholder": {
"type": "plain_text",
"text": "Enter a description..."
}
},
"optional": true,
"hint": {
"type": "plain_text",
"text": "Provide additional context"
}
}
フィールド:
type(必須):常に"input"element(必須):入力エレメント(テキスト入力、セレクト、日付ピッカーなど)label(必須):plain_text オブジェクト。最大 2000 文字block_id(任意):一意の識別子hint(任意):plain_text オブジェクト。最大 2000 文字optional(任意):ブール値。デフォルトは falsedispatch_action(任意):ブール値。変更時に block_actions をディスパッチするかどうか
**サーフェス:**モーダル、メッセージ、ホームタブ
Context ブロック
補足的なコンテキスト情報を表示します。
{
"type": "context",
"elements": [
{
"type": "image",
"image_url": "https://example.com/avatar.png",
"alt_text": "User avatar"
},
{
"type": "mrkdwn",
"text": "Posted by <@U123ABC> on Dec 15, 2025"
}
]
}
フィールド:
type(必須):常に"context"elements(必須):画像/テキストエレメントの配列(最大 10 個)block_id(任意):一意の識別子
**サーフェス:**メッセージ、モーダル、ホームタブ
Divider ブロック
ブロック間の視覚的な区切りです。
{
"type": "divider"
}
**サーフェス:**メッセージ、モーダル、ホームタブ
Image ブロック
画像を表示します。
{
"type": "image",
"image_url": "https://example.com/chart.png",
"alt_text": "Sales chart",
"title": {
"type": "plain_text",
"text": "Q4 Sales Performance"
}
}
フィールド:
type(必須):常に"image"image_url(必須*):公開 URL。最大 3000 文字slack_file(必須*):image_url の代替alt_text(必須):説明。最大 2000 文字title(任意):plain_text オブジェクト。最大 2000 文字block_id(任意):一意の識別子
*image_url または slack_file のいずれかが必須です
**サーフェス:**メッセージ、モーダル、ホームタブ
Markdown ブロック
書式設定された Markdown を表示します(メッセージのみ)。
{
"type": "markdown",
"text": "**Important:** This is *formatted* text with `code`."
}
**サーフェス:**メッセージのみ
Rich Text ブロック
構造化されたテキスト表現です。
{
"type": "rich_text",
"elements": [
{
"type": "rich_text_section",
"elements": [
{
"type": "text",
"text": "Hello ",
"style": {
"bold": true
}
},
{
"type": "user",
"user_id": "U123ABC"
}
]
}
]
}
**サーフェス:**メッセージ、モーダル、ホームタブ
Video ブロック
動画プレーヤーを埋め込みます。
{
"type": "video",
"title": {
"type": "plain_text",
"text": "Product Demo"
},
"video_url": "https://example.com/video.mp4",
"thumbnail_url": "https://example.com/thumb.png",
"alt_text": "Product demonstration video"
}
**サーフェス:**メッセージ、モーダル、ホームタブ
エレメントリファレンス
Button Element
アクションを実行するためのインタラクティブなボタンです。
{
"type": "button",
"text": {
"type": "plain_text",
"text": "Click Me",
"emoji": true
},
"action_id": "button_click",
"value": "button_value",
"style": "primary"
}
フィールド:
type(必須):常に"button"text(必須):plain_textオブジェクト。最大75文字action_id(任意):インタラクションの識別子。最大255文字value(任意):ペイロードの値。最大2000文字style(任意):"primary"(緑)または"danger"(赤)url(任意):開くURL。最大3000文字confirm(任意):確認ダイアログaccessibility_label(任意):スクリーンリーダー用のテキスト。最大75文字
使用先: Section(アクセサリー)、Actions
Static Select Menu
あらかじめ定義されたオプションを表示するドロップダウンです。
{
"type": "static_select",
"action_id": "priority_select",
"placeholder": {
"type": "plain_text",
"text": "Select priority"
},
"options": [
{
"text": {
"type": "plain_text",
"text": "High"
},
"value": "high"
},
{
"text": {
"type": "plain_text",
"text": "Medium"
},
"value": "medium"
},
{
"text": {
"type": "plain_text",
"text": "Low"
},
"value": "low"
}
],
"initial_option": {
"text": {
"type": "plain_text",
"text": "Medium"
},
"value": "medium"
}
}
フィールド:
type(必須):"static_select"action_id(任意):インタラクションの識別子options(必須*):オプションオブジェクトの配列(最大100個)option_groups(必須*):グループ化されたオプション(最大100グループ)initial_option(任意):事前に選択するオプションplaceholder(任意):プレースホルダーテキスト。最大150文字confirm(任意):確認ダイアログfocus_on_load(任意):モーダルで自動的にフォーカス
*optionsまたはoption_groupsのいずれかが必須です
External Select Menu
動的に読み込まれるオプションを表示するドロップダウンです。
{
"type": "external_select",
"action_id": "customer_select",
"placeholder": {
"type": "plain_text",
"text": "Search customers..."
},
"min_query_length": 2
}
フィールド:
type(必須):"external_select"action_id(任意):インタラクションの識別子min_query_length(任意):クエリを送信するまでの最小文字数(デフォルトは3)initial_option(任意):事前に選択するオプションplaceholder(任意):プレースホルダーテキスト
Users Select Menu
ワークスペースのユーザーを選択します。
{
"type": "users_select",
"action_id": "assignee_select",
"placeholder": {
"type": "plain_text",
"text": "Select assignee"
},
"initial_user": "U123ABC"
}
Channels Select Menu
パブリックチャンネルを選択します。
{
"type": "channels_select",
"action_id": "channel_select",
"placeholder": {
"type": "plain_text",
"text": "Select channel"
},
"initial_channel": "C123ABC"
}
Conversations Select Menu
任意の会話(チャンネル、DM、グループ)を選択します。
{
"type": "conversations_select",
"action_id": "conversation_select",
"placeholder": {
"type": "plain_text",
"text": "Select conversation"
},
"default_to_current_conversation": true
}
Multi-Select Menus
すべての選択メニューには、複数選択できるバリエーションがあります。
multi_static_selectmulti_external_selectmulti_users_selectmulti_channels_selectmulti_conversations_select
{
"type": "multi_users_select",
"action_id": "team_select",
"placeholder": {
"type": "plain_text",
"text": "Select team members"
},
"max_selected_items": 5
}
Date Picker
日付を選択します。
{
"type": "datepicker",
"action_id": "due_date",
"placeholder": {
"type": "plain_text",
"text": "Select due date"
},
"initial_date": "2025-12-31"
}
Time Picker
時刻を選択します。
{
"type": "timepicker",
"action_id": "meeting_time",
"placeholder": {
"type": "plain_text",
"text": "Select time"
},
"initial_time": "14:30"
}
Datetime Picker
日付と時刻をまとめて選択します。
{
"type": "datetimepicker",
"action_id": "event_datetime",
"initial_date_time": 1734307200
}
Checkboxes
オプションから複数選択します。
{
"type": "checkboxes",
"action_id": "features_select",
"options": [
{
"text": {
"type": "plain_text",
"text": "Email notifications"
},
"value": "email",
"description": {
"type": "mrkdwn",
"text": "*Receive daily summary*"
}
},
{
"text": {
"type": "plain_text",
"text": "Slack notifications"
},
"value": "slack"
}
],
"initial_options": [
{
"text": {
"type": "plain_text",
"text": "Email notifications"
},
"value": "email"
}
]
}
Radio Buttons
オプションから1つ選択します。
{
"type": "radio_buttons",
"action_id": "urgency_select",
"options": [
{
"text": {
"type": "plain_text",
"text": "Urgent"
},
"value": "urgent"
},
{
"text": {
"type": "plain_text",
"text": "Standard"
},
"value": "standard"
}
],
"initial_option": {
"text": {
"type": "plain_text",
"text": "Standard"
},
"value": "standard"
}
}
Plain Text Input
1行または複数行のテキスト入力です。
{
"type": "plain_text_input",
"action_id": "comment_input",
"placeholder": {
"type": "plain_text",
"text": "Enter your comment..."
},
"multiline": true,
"min_length": 10,
"max_length": 500
}
Number Input
入力値を検証する数値入力です。
{
"type": "number_input",
"action_id": "quantity_input",
"is_decimal_allowed": false,
"min_value": "1",
"max_value": "100",
"placeholder": {
"type": "plain_text",
"text": "Enter quantity"
}
}
URL Input
入力値を検証するURL入力です。
{
"type": "url_text_input",
"action_id": "website_input",
"placeholder": {
"type": "plain_text",
"text": "https://example.com"
}
}
Email Input
入力値を検証するメールアドレス入力です。
{
"type": "email_text_input",
"action_id": "email_input",
"placeholder": {
"type": "plain_text",
"text": "[email protected]"
}
}
Rich Text Input
書式付きテキスト入力です。
{
"type": "rich_text_input",
"action_id": "content_input",
"placeholder": {
"type": "plain_text",
"text": "Write your content..."
}
}
File Input
ファイルをアップロードします(モーダルのみ)。
{
"type": "file_input",
"action_id": "attachment_input",
"filetypes": ["pdf", "png", "jpg"],
"max_files": 3
}
Overflow Menu
補助的なアクション用のコンパクトなメニューです。
{
"type": "overflow",
"action_id": "more_actions",
"options": [
{
"text": {
"type": "plain_text",
"text": "Edit"
},
"value": "edit"
},
{
"text": {
"type": "plain_text",
"text": "Delete"
},
"value": "delete"
}
]
}
Composition Objects
Text Object
Block Kit全体でテキストコンテンツに使用します。
プレーンテキスト:
{
"type": "plain_text",
"text": "Hello, world!",
"emoji": true
}
Markdown(mrkdwn):
{
"type": "mrkdwn",
"text": "*Bold* _italic_ ~strike~ `code` <https://example.com|link>"
}
Confirmation Dialog
破壊的なアクションを実行する前の確認です。
{
"title": {
"type": "plain_text",
"text": "Confirm Delete"
},
"text": {
"type": "mrkdwn",
"text": "Are you sure you want to delete this item? This cannot be undone."
},
"confirm": {
"type": "plain_text",
"text": "Delete"
},
"deny": {
"type": "plain_text",
"text": "Cancel"
},
"style": "danger"
}
Option Object
選択メニュー、チェックボックス、ラジオボタンに使用します。
{
"text": {
"type": "plain_text",
"text": "Option Label"
},
"value": "option_value",
"description": {
"type": "plain_text",
"text": "Optional description"
},
"url": "https://example.com"
}
Option Group
選択メニュー用のグループ化されたオプションです。
{
"label": {
"type": "plain_text",
"text": "Group Label"
},
"options": [
{
"text": {
"type": "plain_text",
"text": "Option 1"
},
"value": "option_1"
}
]
}
Modal Reference
モーダルを開く
{
"type": "modal",
"callback_id": "feedback_modal",
"title": {
"type": "plain_text",
"text": "Submit Feedback"
},
"submit": {
"type": "plain_text",
"text": "Submit"
},
"close": {
"type": "plain_text",
"text": "Cancel"
},
"blocks": [
{
"type": "input",
"block_id": "feedback_type",
"label": {
"type": "plain_text",
"text": "Feedback Type"
},
"element": {
"type": "static_select",
"action_id": "type_select",
"options": [
{
"text": {
"type": "plain_text",
"text": "Bug Report"
},
"value": "bug"
},
{
"text": {
"type": "plain_text",
"text": "Feature Request"
},
"value": "feature"
}
]
}
},
{
"type": "input",
"block_id": "feedback_content",
"label": {
"type": "plain_text",
"text": "Description"
},
"element": {
"type": "plain_text_input",
"action_id": "content_input",
"multiline": true
}
}
]
}
モーダルのフィールド
type(必須):常に"modal"title(必須):plain_text。最大24文字blocks(必須):ブロックの配列(最大100個)callback_id(任意):view_submissionの識別子submit(任意):送信ボタンのテキスト。最大24文字close(任意):閉じるボタンのテキスト。最大24文字private_metadata(任意):送信時に渡される文字列。最大3000文字clear_on_close(任意):閉じるときにすべてのビューをクリアnotify_on_close(任意):view_closedイベントを送信external_id(任意):カスタム識別子submit_disabled(任意):初期状態で送信ボタンを無効化
slack-block-builder Library
インストール
npm install slack-block-builder
インポート
import {
Message,
Modal,
HomeTab,
Blocks,
Elements,
Bits,
Md
} from 'slack-block-builder';
メッセージの構築
const message = Message({ channel: 'C123ABC', text: 'Fallback text' })
.blocks(
Blocks.Header({ text: 'Welcome!' }),
Blocks.Section({ text: 'Hello, *world*!' }),
Blocks.Divider(),
Blocks.Actions()
.elements(
Elements.Button({ text: 'Click Me', actionId: 'click' })
.primary()
)
)
.buildToObject();
モーダルの構築
const modal = Modal({ title: 'My Form', callbackId: 'form_submit' })
.submit('Save')
.close('Cancel')
.blocks(
Blocks.Input({ label: 'Name', blockId: 'name_block' })
.element(
Elements.TextInput({ actionId: 'name_input' })
.placeholder('Enter your name')
),
Blocks.Input({ label: 'Priority', blockId: 'priority_block' })
.element(
Elements.StaticSelect({ actionId: 'priority_select' })
.options(
Bits.Option({ text: 'High', value: 'high' }),
Bits.Option({ text: 'Medium', value: 'medium' }),
Bits.Option({ text: 'Low', value: 'low' })
)
)
)
.buildToObject();
Markdownヘルパー
import { Md } from 'slack-block-builder';
Md.bold('text') // *text*
Md.italic('text') // _text_
Md.strike('text') // ~text~
Md.code('text') // `text`
Md.codeBlock('text') // ```text```
Md.link('url', 'text') // <url|text>
Md.user('U123') // <@U123>
Md.channel('C123') // <#C123>
Md.emoji('smile') // :smile:
Md.listBullet(['a', 'b']) // • a\n• b
ビルドメソッド
// Returns JavaScript object
modal.buildToObject();
// Returns JSON string
modal.buildToJSON();
// Returns only blocks array
modal.getBlocks();
ベストプラクティス
命名規則
action_id:{verb}_{noun}- 例:submit_form、select_priorityblock_id:{noun}_block- 例:name_block、options_blockcallback_id:{feature}_{action}- 例:feedback_submit
パフォーマンス
- メッセージは50ブロック未満にしてください
- モーダルは100ブロック未満にしてください
- 選択肢が多い場合(100項目超)は、external_selectを使用してください
- トラフィックの多いメッセージでは画像の使用を最小限にしてください
アクセシビリティ
- 画像には必ず
alt_textを指定してください - アイコン付きボタンには
accessibility_labelを使用してください - 十分な色のコントラストを確保してください
- 明確でわかりやすいラベルを付けてください
モバイルでの考慮事項
- テキストは短めにしてください(ボタンでは約30文字で切り詰められます)
- Sectionブロック内のフィールド数を制限してください(最大2~3個)
- モバイル版Slackクライアントでテストしてください
- 複雑な入れ子状のレイアウトは避けてください
よくあるパターン
アクション付き通知
Message({ channel, text: 'New request' })
.blocks(
Blocks.Header({ text: 'New Request' }),
Blocks.Section()
.fields([
`*From:*\n${requester}`,
`*Priority:*\n${priority}`
]),
Blocks.Context()
.elements([`Submitted ${timestamp}`]),
Blocks.Divider(),
Blocks.Actions()
.elements(
Elements.Button({ text: 'Approve', actionId: 'approve' }).primary(),
Elements.Button({ text: 'Reject', actionId: 'reject' }).danger()
)
)
.buildToObject();
バリデーション付きフォームモーダル
Modal({ title: 'Create Task', callbackId: 'task_create' })
.submit('Create')
.close('Cancel')
.blocks(
Blocks.Input({ label: 'Task Name', blockId: 'name' })
.element(Elements.TextInput({ actionId: 'name_input' })),
Blocks.Input({ label: 'Assignee', blockId: 'assignee' })
.element(Elements.UsersSelect({ actionId: 'assignee_select' })),
Blocks.Input({ label: 'Due Date', blockId: 'due_date' })
.element(Elements.DatePicker({ actionId: 'date_select' }))
.optional(true)
)
.buildToObject();
ホームタブのダッシュボード
HomeTab()
.blocks(
Blocks.Header({ text: `Welcome, ${userName}!` }),
Blocks.Section({ text: 'Here are your pending tasks:' }),
Blocks.Divider(),
...tasks.map(task =>
Blocks.Section({ text: `• ${task.title}` })
.accessory(
Elements.Button({ text: 'Complete', actionId: `complete_${task.id}` })
)
),
Blocks.Divider(),
Blocks.Actions()
.elements(
Elements.Button({ text: 'New Task', actionId: 'new_task' }).primary()
)
)
.buildToObject();
トラブルシューティング
よくあるエラー
| エラー | 原因 | 解決方法 |
|---|---|---|
invalid_blocks | 不正なJSON | Block Kit Builderで検証する |
too_many_blocks | 上限超過 | 50(メッセージ)または100(モーダル)に減らす |
invalid_element | ブロック内の要素が不適切 | 要素とブロックの互換性を確認する |
missing_text | 必須のテキストがない | Sectionにテキストまたはフィールドを追加する |
検証のヒント
- Block Kit BuilderでJSONをテストする
- 要素とブロックの互換性を確認する
- 必須フィールドが存在することを確認する
- 表示上の問題がないか、モバイルでテストする
リソース
リファレンスドキュメント
詳しいガイドについては、references/ディレクトリを参照してください。
- blocks.md - すべてのブロックタイプに関する詳細なドキュメント
- interactive-components.md - インタラクティブ要素の完全ガイド
- layout-patterns.md - 構成と入れ子に関するベストプラクティス
- surfaces.md - メッセージ、モーダル、ホームタブの詳細