slack-api-3-interactive-components-and-actions
Sub-skill of slack-api: 3. Interactive Components and Actions.
Best use case
slack-api-3-interactive-components-and-actions is best used when you need a repeatable AI agent workflow instead of a one-off prompt.
Sub-skill of slack-api: 3. Interactive Components and Actions.
Teams using slack-api-3-interactive-components-and-actions should expect a more consistent output, faster repeated execution, less prompt rewriting.
When to use this skill
- You want a reusable workflow that can be run more than once with consistent structure.
When not to use this skill
- You only need a quick one-off answer and do not need a reusable workflow.
- You cannot install or maintain the underlying files, dependencies, or repository context.
Installation
Claude Code / Cursor / Codex
Manual Installation
- Download SKILL.md from GitHub
- Place it in
.claude/skills/3-interactive-components-and-actions/SKILL.mdinside your project - Restart your AI agent — it will auto-discover the skill
How slack-api-3-interactive-components-and-actions Compares
| Feature / Agent | slack-api-3-interactive-components-and-actions | Standard Approach |
|---|---|---|
| Platform Support | Not specified | Limited / Varies |
| Context Awareness | High | Baseline |
| Installation Complexity | Unknown | N/A |
Frequently Asked Questions
What does this skill do?
Sub-skill of slack-api: 3. Interactive Components and Actions.
Where can I find the source code?
You can find the source code on GitHub using the link provided at the top of the page.
SKILL.md Source
# 3. Interactive Components and Actions
## 3. Interactive Components and Actions
```python
# interactive.py
# ABOUTME: Handle interactive components like buttons, selects, modals
# ABOUTME: Implements approval workflows with state management
from slack_bolt import App
from datetime import datetime
import json
import os
app = App(token=os.environ.get("SLACK_BOT_TOKEN"))
# In-memory storage (use database in production)
approval_requests = {}
@app.action("approve_request")
def handle_approve(ack, body, client, logger):
"""Handle approval button click"""
ack()
user = body['user']['id']
request_id = body['actions'][0]['value']
channel = body['channel']['id']
message_ts = body['message']['ts']
# Update the message to show approval
updated_blocks = body['message']['blocks'].copy()
# Remove action buttons
updated_blocks = [b for b in updated_blocks if b.get('type') != 'actions']
# Add approval status
updated_blocks.append({
"type": "section",
"text": {
"type": "mrkdwn",
"text": f":white_check_mark: *Approved* by <@{user}> at {datetime.now().strftime('%Y-%m-%d %H:%M')}"
}
})
# Update the original message
client.chat_update(
channel=channel,
ts=message_ts,
blocks=updated_blocks,
text="Request approved"
)
# Store approval
approval_requests[request_id] = {
"status": "approved",
"approved_by": user,
"timestamp": datetime.now().isoformat()
}
logger.info(f"Request {request_id} approved by {user}")
@app.action("reject_request")
def handle_reject(ack, body, client, respond):
"""Handle rejection with reason modal"""
ack()
request_id = body['actions'][0]['value']
trigger_id = body['trigger_id']
# Open modal for rejection reason
client.views_open(
trigger_id=trigger_id,
view={
"type": "modal",
"callback_id": f"reject_modal_{request_id}",
"title": {
"type": "plain_text",
"text": "Reject Request"
},
"submit": {
"type": "plain_text",
"text": "Reject"
},
"close": {
"type": "plain_text",
"text": "Cancel"
},
"blocks": [
{
"type": "input",
"block_id": "reason_block",
"element": {
"type": "plain_text_input",
"action_id": "rejection_reason",
"multiline": True,
"placeholder": {
"type": "plain_text",
"text": "Enter reason for rejection..."
}
},
"label": {
"type": "plain_text",
"text": "Rejection Reason"
}
}
],
"private_metadata": json.dumps({
"channel": body['channel']['id'],
"message_ts": body['message']['ts'],
"request_id": request_id
})
}
)
@app.view_submission("reject_modal_.*")
def handle_reject_submission(ack, body, client, view, logger):
"""Handle rejection modal submission"""
ack()
# Get values from modal
reason = view['state']['values']['reason_block']['rejection_reason']['value']
metadata = json.loads(view['private_metadata'])
user = body['user']['id']
channel = metadata['channel']
message_ts = metadata['message_ts']
request_id = metadata['request_id']
# Update original message
client.chat_postMessage(
channel=channel,
thread_ts=message_ts,
text=f":x: *Rejected* by <@{user}>\n*Reason:* {reason}"
)
# Update the original message blocks
original_message = client.conversations_history(
channel=channel,
latest=message_ts,
inclusive=True,
limit=1
)
if original_message['messages']:
updated_blocks = original_message['messages'][0].get('blocks', [])
updated_blocks = [b for b in updated_blocks if b.get('type') != 'actions']
updated_blocks.append({
"type": "section",
"text": {
"type": "mrkdwn",
"text": f":x: *Rejected* by <@{user}>"
}
})
client.chat_update(
channel=channel,
ts=message_ts,
blocks=updated_blocks,
text="Request rejected"
)
logger.info(f"Request {request_id} rejected by {user}: {reason}")
@app.action("poll_vote")
def handle_poll_vote(ack, body, logger):
"""Handle poll vote selection"""
ack()
selected = body['actions'][0]['selected_option']['value']
logger.info(f"Poll vote: {selected}")
@app.action("submit_vote")
def handle_submit_vote(ack, body, client, respond):
"""Handle poll submission"""
ack()
user = body['user']['id']
# Get selected option from state
state = body.get('state', {}).get('values', {})
selected = None
for block_id, block_values in state.items():
for action_id, action_value in block_values.items():
if action_value.get('selected_option'):
selected = action_value['selected_option']
if selected:
respond(
*Content truncated — see parent skill for full reference.*Related Skills
interactive-report-generator
Generate interactive HTML reports with Plotly visualizations from data analysis results. Supports dashboards, charts, and professional styling.
interactive-Codex-to-file-based-fallback
Switch from tmux/interactive Codex to file-based Codex -p execution when interactive runs fail with upstream errors or analysis-only stalls, then verify landing from git/GitHub state.
interactive-issue-execution-worktree-guardrails
Execute approved GitHub issues in isolated worktrees with interactive Codex/Codex runs, while containing agent drift and salvaging progress when provider/runtime problems occur.
github-actions-trigger-and-shell-gotchas
Prevent false verification gaps in GitHub Actions by checking push path filters, shell compatibility, and shared CI environment failures before concluding a workflow fix worked or failed.
github-actions-cross-platform-validation-gotchas
Execution-time GitHub Actions pitfalls discovered while fixing cross-platform CI workflows — path-filter non-triggers, Windows shell parsing mismatches, and job-scoped validation.
interactive-dashboard-builder
Create self-contained HTML/JavaScript dashboards with Chart.js, filters, and professional styling
slack-gif-creator
Create custom animated GIFs for Slack reactions and celebrations. Use for team milestones, custom emoji reactions, inside jokes, and workplace fun.
web-artifacts-builder-1-interactive-dashboard
Sub-skill of web-artifacts-builder: 1. Interactive Dashboard (+1).
interactive-menu-builder-5-confirmation-dialogs
Sub-skill of interactive-menu-builder: 5. Confirmation Dialogs (+1).
interactive-menu-builder-3-table-display
Sub-skill of interactive-menu-builder: 3. Table Display (+1).
interactive-menu-builder-2-multi-level-menu-system
Sub-skill of interactive-menu-builder: 2. Multi-Level Menu System.
interactive-menu-builder-1-consistent-navigation
Sub-skill of interactive-menu-builder: 1. Consistent Navigation (+3).