Skip to content

Instantly share code, notes, and snippets.

@renatorib
Created January 6, 2026 16:31
Show Gist options
  • Select an option

  • Save renatorib/62d68ea5ab08aa1d4c4c25cb3366e5df to your computer and use it in GitHub Desktop.

Select an option

Save renatorib/62d68ea5ab08aa1d4c4c25cb3366e5df to your computer and use it in GitHub Desktop.
Slack Block Kit TypeScript Types
// JSON Schema:
// https://gist.githubusercontent.com/lawrencegripper/ee24242249fc6a1a0a73c561766dd486/raw/54e8dea65f4b8a0d9eae0e4be656568076142999/blockkit.schema.json
interface Actionable {
action_id?: string;
}
interface Focusable {
focus_on_load?: boolean;
}
interface Placeholdable {
placeholder?: PlainTextElement;
}
export interface PlainTextElement {
type: 'plain_text';
text: string;
emoji?: boolean;
}
export interface MrkdwnElement {
type: 'mrkdwn';
text: string;
verbatim?: boolean;
}
export type TextElement = PlainTextElement | MrkdwnElement;
export interface ConfirmationDialog {
title?: PlainTextElement;
text: TextElement;
confirm?: PlainTextElement;
deny?: PlainTextElement;
style?: 'primary' | 'danger';
}
export interface Button {
type: 'button';
text: PlainTextElement;
action_id?: string;
url?: string;
value?: string;
style?: 'danger' | 'primary';
confirm?: ConfirmationDialog;
accessibility_label?: string;
}
export interface Checkboxes extends Actionable, Focusable {
type: 'checkboxes';
options: Option[];
initial_options?: Option[];
confirm?: ConfirmationDialog;
}
export type Option = PlainTextOption | MrkdwnOption;
export interface PlainTextOption {
text: PlainTextElement;
value: string;
description?: PlainTextElement;
url?: string;
}
export interface MrkdwnOption {
text: MrkdwnElement;
value: string;
description?: PlainTextElement;
url?: string;
}
export interface StaticSelect extends Actionable, Focusable, Placeholdable {
type: 'static_select';
options: PlainTextOption[];
initial_option?: PlainTextOption;
}
export interface UsersSelect extends Actionable, Focusable, Placeholdable {
type: 'users_select';
initial_user?: string;
}
export interface ConversationsSelect extends Actionable, Focusable, Placeholdable {
type: 'conversations_select';
initial_conversation?: string;
default_to_current_conversation?: boolean;
}
export interface ChannelsSelect extends Actionable, Focusable, Placeholdable {
type: 'channels_select';
initial_channel?: string;
}
export interface ExternalSelect extends Actionable, Focusable, Placeholdable {
type: 'external_select';
initial_option?: PlainTextOption;
min_query_length?: number;
}
export type Select = StaticSelect | UsersSelect | ConversationsSelect | ChannelsSelect | ExternalSelect;
export type MultiSelect =
| (Omit<StaticSelect, 'type' | 'initial_option'> & {
type: 'multi_static_select';
initial_options?: PlainTextOption[];
})
| (Omit<UsersSelect, 'type' | 'initial_user'> & { type: 'multi_users_select'; initial_users?: string[] })
| (Omit<ConversationsSelect, 'type' | 'initial_conversation'> & {
type: 'multi_conversations_select';
initial_conversations?: string[];
})
| (Omit<ChannelsSelect, 'type' | 'initial_channel'> & { type: 'multi_channels_select'; initial_channels?: string[] })
| (Omit<ExternalSelect, 'type' | 'initial_option'> & {
type: 'multi_external_select';
initial_options?: PlainTextOption[];
});
// Elements
export interface ImageElement {
type: 'image';
image_url: string;
alt_text: string;
}
export interface Datepicker extends Focusable, Placeholdable {
type: 'datepicker';
action_id?: string;
initial_date?: string;
confirm?: ConfirmationDialog;
}
export interface Timepicker extends Focusable, Placeholdable {
type: 'timepicker';
action_id?: string;
initial_time?: string;
timezone?: string;
confirm?: ConfirmationDialog;
}
export interface DateTimepicker extends Focusable {
type: 'datetimepicker';
action_id?: string;
initial_date_time?: number;
confirm?: ConfirmationDialog;
}
export interface Overflow {
type: 'overflow';
action_id?: string;
options: Option[];
confirm?: ConfirmationDialog;
}
export interface RadioButtons extends Focusable {
type: 'radio_buttons';
action_id?: string;
options: Option[];
initial_option?: Option;
confirm?: ConfirmationDialog;
}
export interface WorkflowButton {
type: 'workflow_button';
text: PlainTextElement;
workflow: {
trigger: {
url: string;
customizable_input_parameters?: Array<{
name: string;
value: string;
}>;
};
};
style?: 'danger' | 'primary';
confirm?: ConfirmationDialog;
accessibility_label?: string;
}
export interface DispatchActionConfig {
trigger_actions_on?: Array<'on_enter_pressed' | 'on_character_entered'>;
}
export interface PlainTextInput {
type: 'plain_text_input';
action_id?: string;
placeholder?: PlainTextElement;
initial_value?: string;
multiline?: boolean;
min_length?: number;
max_length?: number;
dispatch_action_config?: DispatchActionConfig;
focus_on_load?: boolean;
}
export interface URLInput {
type: 'url_text_input';
action_id?: string;
initial_value?: string;
placeholder?: PlainTextElement;
dispatch_action_config?: DispatchActionConfig;
focus_on_load?: boolean;
}
export interface EmailInput {
type: 'email_text_input';
action_id?: string;
initial_value?: string;
placeholder?: PlainTextElement;
dispatch_action_config?: DispatchActionConfig;
focus_on_load?: boolean;
}
export interface NumberInput {
type: 'number_input';
action_id?: string;
is_decimal_allowed: boolean;
initial_value?: string;
min_value?: string;
max_value?: string;
placeholder?: PlainTextElement;
dispatch_action_config?: DispatchActionConfig;
focus_on_load?: boolean;
}
// Rich Text Types
export interface RichTextStyle {
bold?: boolean;
italic?: boolean;
strike?: boolean;
highlight?: boolean;
}
export interface RichTextBroadcastMention {
type: 'broadcast';
range: 'here' | 'channel' | 'everyone';
style?: RichTextStyle;
}
export interface RichTextColor {
type: 'color';
value: string;
style?: RichTextStyle;
}
export interface RichTextChannelMention {
type: 'channel';
channel_id: string;
style?: RichTextStyle;
}
export interface RichTextDate {
type: 'date';
timestamp: number;
format: string;
style?: RichTextStyle;
url?: string;
fallback?: string;
}
export interface RichTextEmoji {
type: 'emoji';
name: string;
style?: RichTextStyle;
unicode?: string;
url?: string;
}
export interface RichTextLink {
type: 'link';
url: string;
style?: RichTextStyle;
text?: string;
unsafe?: boolean;
}
export interface RichTextTeamMention {
type: 'team';
team_id: string;
style?: RichTextStyle;
}
export interface RichTextText {
type: 'text';
text: string;
style?: RichTextStyle;
}
export interface RichTextUserMention {
type: 'user';
user_id: string;
style?: RichTextStyle;
}
export interface RichTextUsergroupMention {
type: 'usergroup';
usergroup_id: string;
style?: RichTextStyle;
}
export type RichTextElement =
| RichTextBroadcastMention
| RichTextColor
| RichTextChannelMention
| RichTextDate
| RichTextEmoji
| RichTextLink
| RichTextTeamMention
| RichTextText
| RichTextUserMention
| RichTextUsergroupMention;
export interface RichTextSection {
type: 'rich_text_section';
elements: RichTextElement[];
}
export interface RichTextList {
type: 'rich_text_list';
style: 'bullet' | 'ordered';
indent?: number;
border?: number;
elements: RichTextSection[];
}
export interface RichTextQuote {
type: 'rich_text_quote';
elements: RichTextElement[];
}
export interface RichTextPreformatted {
type: 'rich_text_preformatted';
elements: RichTextElement[];
border?: number;
}
export interface RichTextInput {
type: 'rich_text_input';
action_id?: string;
placeholder?: PlainTextElement;
initial_value?: RichTextBlock;
dispatch_action_config?: DispatchActionConfig;
focus_on_load?: boolean;
}
// Blocks
export type KnownBlock =
| ImageBlock
| ContextBlock
| ActionsBlock
| DividerBlock
| SectionBlock
| InputBlock
| FileBlock
| HeaderBlock
| VideoBlock
| RichTextBlock;
export interface BaseBlock {
block_id?: string;
}
export interface ImageBlock extends BaseBlock {
type: 'image';
image_url: string;
alt_text: string;
title?: PlainTextElement;
}
export interface ContextBlock extends BaseBlock {
type: 'context';
elements: (ImageElement | TextElement)[];
}
export interface ActionsBlock extends BaseBlock {
type: 'actions';
elements: (
| Button
| Checkboxes
| Select
| MultiSelect
| Datepicker
| DateTimepicker
| Timepicker
| Overflow
| RadioButtons
| WorkflowButton
| RichTextInput
)[];
}
export interface SectionBlock extends BaseBlock {
type: 'section';
text?: TextElement;
fields?: TextElement[];
accessory?:
| Button
| Overflow
| Datepicker
| Timepicker
| Select
| MultiSelect
| ImageElement
| RadioButtons
| Checkboxes;
}
export interface DividerBlock extends BaseBlock {
type: 'divider';
}
export interface HeaderBlock extends BaseBlock {
type: 'header';
text: PlainTextElement;
}
export interface InputBlock extends BaseBlock {
type: 'input';
label: PlainTextElement;
element:
| Select
| MultiSelect
| Datepicker
| Timepicker
| DateTimepicker
| PlainTextInput
| URLInput
| EmailInput
| NumberInput
| RadioButtons
| Checkboxes
| RichTextInput;
hint?: PlainTextElement;
optional?: boolean;
dispatch_action?: boolean;
}
export interface FileBlock extends BaseBlock {
type: 'file';
source: string;
external_id: string;
}
export interface VideoBlock extends BaseBlock {
type: 'video';
video_url: string;
thumbnail_url: string;
alt_text: string;
title: PlainTextElement;
title_url?: string;
author_name?: string;
provider_name?: string;
provider_icon_url?: string;
description?: PlainTextElement;
}
export interface RichTextBlock extends BaseBlock {
type: 'rich_text';
elements: (RichTextSection | RichTextList | RichTextQuote | RichTextPreformatted)[];
}
// Resulting Root Type
export type SlackMessageBlocks = KnownBlock[];
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment