Slack surfaces are composed of blocks, elements and composition objects. Surfs exposes the following components for creating interfaces in Slack applications:
Instead of exhaustive property documentation, this reference will try to direct to Slack's documentation while providing examples of usage. In addition to this, a brief code snippet will be given to explore a component's props via clojure.spec.
Slack documenation for composition objects.
Renders to a text object.
Props:
(thlack.surfs.repl/props :text)
Usage:
; Input
[:text "Hello!"]
; Output
{:type :plain_text :text "Hello"}
The text component supports markdown and plain text explicitly as a simple prop passthrough:
; Input
[:text {:type :plain_text :text "Hello" :emoji false}]
; Output
{:type :plain_text :text "Hello" :emoji false}
; Input
[:text {:type :mrkdwn :text "# Hello" :verbatim false}]
; Output
{:type :mrkdwn :text "# Hello" :verbatim false}
It may be more convenient to use the more explicit plain-text and markdown components.
Renders to a text object.
Usage:
; Input
[:plain-text "Hello"]
; Output
{:type :plain_text :text "Hello" :emoji true}
; Input
[:plain-text "Goodbye" false]
; Output
{:type :plain_text :text "Goodbye" :emoji false}
; Input
[:plain-text {:text "Greetings" :emoji false}]
; Output
{:type :plain_text :text "Greetings" :emoji false}
Aliases:
[:label]
[:placeholder]
[:hint]
[:title]
Renders to a text object.
Usage:
; Input
[:markdown "# Hello"]
; Output
{:type :mrkdwn :text "# Hello" :verbatim false}
; Input
[:markdown "# Goodbye" true]
; Output
{:type :mrkdwn :text "# Goodbye" :verbatim true}
; Input
[:markdown {:text "# Greetings" :verbatim true}]
; Output
{:type :mrkdwn :text "# Greetings" :verbatim true}
Renders a confirmation dialog object.
Props:
(thlack.surfs.repl/props :confirm)
Children:
Child | Required | Description |
---|---|---|
text | * | Can be a text component or a string literal. |
Usage:
; Input
[:confirm {:confirm "Ok!" :deny "Nah!" :title "This is a title!" :style :primary}
[:text "Are you sure?"]]
[:confirm {:confirm "Ok!" :deny "Nah!" :title "This is a title!" :style :primary} "Are you sure?"]
; Output
{:confirm {:type :plain_text :text "Ok!" :emoji true}
:deny {:type :plain_text :text "Nah!" :emoji true}
:title {:type :plain_text :text "This is a title!" :emoji true}
:text {:type :plain_text :text "Are you sure?"}
:style :primary}
Confirms plain text props - that is :title
, :confirm
, and :deny
- assume a default value of
true
for the :emoji
prop. See docs for the disable_emoji_for prop.
Renders an option object.
Props
(thlack.surfs.repl/props :option)
Children
Child | Required | Description |
---|---|---|
text | * | Can be a text component or a string literal. |
Usage
; Input
[:option {:value "1" :description "Oh hello"} "Label"]
; Output
{:value "1",
:description {:type :plain_text, :text "Oh hello", :emoji true},
:text {:type :plain_text, :text "Label"}}
Render an option group object.
Children
Child | Required | Description |
---|---|---|
label | * | |
option |
Usage
; Input
[:option-group
[:label "Pizza Toppings"]
[:option {:value "1"} "Mushrooms"]
[:option {:value "2"} "Pepperoni"]]
; Output
{:label {:type :plain_text, :text "Pizza Toppings", :emoji true},
:options
[{:value "1", :text {:type :plain_text, :text "Mushrooms"}}
{:value "2", :text {:type :plain_text, :text "Pepperoni"}}]}
Slack documentation for block elements.
Renders a button element.
Props:
(thlack.surfs.repl/props :button)
The :button
component can safely omit the :action_id
prop (and thus all props). If :action_id
is not provided, a uuid string will be generated. This simplifies cases where the button action_id may be ignored - as is the case with buttons that are used for opening urls.
Children:
Child | Required | Description |
---|---|---|
text | * | Provided as a text component or a string literal. |
confirm |
Usage:
; Input
[:button {:action_id "A123" :value "1"} "Click Me!"]
; Output
{:action_id "A123"
:value "1"
:type :button
:text {:type :plain_text
:text "Click Me!"}}
; Input
[:button {:action_id "A123" :value "1"}
[:confirm {:confirm "Ok!" :deny "Nah!" :title "You sure?!?!?"}
[:text "This is irreversible!"]]
"Click Me!"]
; Output
{:action_id "A123",
:value "1",
:type :button,
:text {:type :plain_text, :text "Click Me!"},
:confirm
{:confirm {:type :plain_text, :text "Ok!", :emoji true},
:deny {:type :plain_text, :text "Nah!", :emoji true},
:title {:type :plain_text, :text "You sure?!?!?", :emoji true},
:text {:type :plain_text, :text "This is irreversible!"},
:style :primary}}
; Input
[:button "Click me"]
; Output
{:type :button,
:action_id "58113279-334f-42bf-aa25-95b48bf42481",
:text {:type :plain_text, :text "Click me"}}
Renders a checkbox group.
Props
(thlack.surfs.repl/props :checkboxes)
Children
Child | Required | Description |
---|---|---|
option | * (requires at least one option) | |
confirm |
Usage
; Input
[:checkboxes {:action_id "A123"}
[:option {:value "1"} "Mushrooms"]
[:option {:value "2" :selected? true} "Pepperoni"]]
; Output
{:action_id "A123",
:type :checkboxes,
:options
({:value "1", :text {:type :plain_text, :text "Mushrooms"}}
{:value "2", :text {:type :plain_text, :text "Pepperoni"}}),
:initial_options ({:value "2", :text {:type :plain_text, :text "Pepperoni"}})}
; Input
[:checkboxes {:action_id "A123"}
[:option {:value "1"} "Mushrooms"]
[:option {:value "2" :selected? true} "Pepperoni"]
[:confirm {:confirm "Ok!" :deny "Nah!" :title "You sure?!?!?"}
[:text "This is irreversible!"]]]
; Output
{:action_id "A123",
:type :checkboxes,
:confirm
{:confirm {:type :plain_text, :text "Ok!", :emoji true},
:deny {:type :plain_text, :text "Nah!", :emoji true},
:title {:type :plain_text, :text "You sure?!?!?", :emoji true},
:text {:type :plain_text, :text "This is irreversible!"},
:style :primary},
:options
({:value "1", :text {:type :plain_text, :text "Mushrooms"}}
{:value "2", :text {:type :plain_text, :text "Pepperoni"}}),
:initial_options ({:value "2", :text {:type :plain_text, :text "Pepperoni"}})}
Renders a date picker element.
Props
(thlack.surfs.repl/props :datepicker)
Children
Child | Required | Description |
---|---|---|
placeholder | ||
confirm |
Usage
; Input
[:datepicker {:action_id "A123" :initial_date "2020-11-30"}
[:placeholder "The date"]]
; Output
{:action_id "A123",
:initial_date "2020-11-30",
:type :datepicker,
:placeholder {:type :plain_text, :text "The date", :emoji true}}
; Input
[:datepicker {:action_id "A123" :initial_date "2020-11-30"}
[:placeholder "The date"]
[:confirm {:confirm "Ok!" :deny "Nah!" :title "You sure?!?!?"}
[:text "This is irreversible!"]]]
; Output
{:action_id "A123",
:initial_date "2020-11-30",
:type :datepicker,
:confirm
{:confirm {:type :plain_text, :text "Ok!", :emoji true},
:deny {:type :plain_text, :text "Nah!", :emoji true},
:title {:type :plain_text, :text "You sure?!?!?", :emoji true},
:text {:type :plain_text, :text "This is irreversible!"},
:style :primary},
:placeholder {:type :plain_text, :text "The date", :emoji true}}
Renders an image element.
Props
(thlack.surfs.repl/props :img)
Usage
; Input
[:img {:image_url "http://www.fillmurray.com/200/300" :alt_text "It's Bill Murray"}]
; Output
{:image_url "http://www.fillmurray.com/200/300", :alt_text "It's Bill Murray", :type :image}
Renders a static multi select element.
Props
(thlack.surfs.repl/props :multi-static-select)
**Children**
Child | Required | Description
------|----------|------------
[placeholder](#plain-text)| * |
[option-group](#option-group)| | Required if not using `:option`
[option](#option)| | Required if not using `:option-group`
[confirm](#confirm)|
**Usage**
```clojure
; Input
[:multi-static-select {:action_id "A123" :max_selected_items 5}
[:placeholder "Pizza Toppings"]
[:option {:value "1"} "Mushrooms"]
[:option {:value "2" :selected? true} "Pepperoni"]
[:option {:value "3" :selected? true} "Cheese"]]
; Output
{:action_id "A123",
:max_selected_items 5,
:type :multi_static_select,
:options
({:value "1", :text {:type :plain_text, :text "Mushrooms"}}
{:value "2", :text {:type :plain_text, :text "Pepperoni"}}
{:value "3", :text {:type :plain_text, :text "Cheese"}}),
:placeholder {:type :plain_text, :text "Pizza Toppings", :emoji true},
:initial_options
({:value "2", :text {:type :plain_text, :text "Pepperoni"}} {:value "3", :text {:type :plain_text, :text "Cheese"}})}
; Input
[:multi-static-select {:action_id "A123" :max_selected_items 5}
[:placeholder "Pizza Toppings"]
[:option-group
[:label "Veggies"]
[:option {:value "1"} "Mushrooms"]
[:option {:value "2" :selected? true} "Peppers"]]
[:option-group
[:label "Meats"]
[:option {:value "3"} "Pepperoni"]
[:option {:value "4" :selected? true} "Ham"]]]
; Output
{:action_id "A123",
:max_selected_items 5,
:type :multi_static_select,
:option_groups
({:label {:type :plain_text, :text "Veggies", :emoji true},
:options
[{:value "1", :text {:type :plain_text, :text "Mushrooms"}}
{:value "2", :text {:type :plain_text, :text "Peppers"}}]}
{:label {:type :plain_text, :text "Meats", :emoji true},
:options
[{:value "3", :text {:type :plain_text, :text "Pepperoni"}}
{:value "4", :text {:type :plain_text, :text "Ham"}}]}),
:placeholder {:type :plain_text, :text "Pizza Toppings", :emoji true},
:initial_options
({:value "2", :text {:type :plain_text, :text "Peppers"}} {:value "4", :text {:type :plain_text, :text "Ham"}})}
; Input
[:multi-static-select {:action_id "A123" :max_selected_items 5}
[:placeholder "Pizza Toppings"]
[:option {:value "1"} "Mushrooms"]
[:option {:value "2" :selected? true} "Pepperoni"]
[:option {:value "3" :selected? true} "Cheese"]
[:confirm {:confirm "Ok!" :deny "Nah!" :title "You sure?!?!?"}
[:text "This is irreversible!"]]]
; Output
{:action_id "A123",
:max_selected_items 5,
:type :multi_static_select,
:confirm
{:confirm {:type :plain_text, :text "Ok!", :emoji true},
:deny {:type :plain_text, :text "Nah!", :emoji true},
:title {:type :plain_text, :text "You sure?!?!?", :emoji true},
:text {:type :plain_text, :text "This is irreversible!"},
:style :primary},
:options
({:value "1", :text {:type :plain_text, :text "Mushrooms"}}
{:value "2", :text {:type :plain_text, :text "Pepperoni"}}
{:value "3", :text {:type :plain_text, :text "Cheese"}}),
:placeholder {:type :plain_text, :text "Pizza Toppings", :emoji true},
:initial_options
({:value "2", :text {:type :plain_text, :text "Pepperoni"}} {:value "3", :text {:type :plain_text, :text "Cheese"}})}
Renders an external multi select element.
Props
(thlack.surfs.repl/props :multi-external-select)
Children
Child | Required | Description |
---|---|---|
placeholder | * | |
option | All option elements are considered initial_options | |
confirm |
Usage
; Input
[:multi-external-select {:action_id "A123" :max_selected_items 5 :min_query_length 3}
[:placeholder "Pizza Toppings"]
[:option {:value "1"} "Pepperoni"]
[:option {:value "2"} "Mushrooms"]]
; Output
{:action_id "A123",
:max_selected_items 5,
:min_query_length 3,
:type :multi_external_select,
:placeholder {:type :plain_text, :text "Pizza Toppings", :emoji true},
:initial_options
({:value "1", :text {:type :plain_text, :text "Pepperoni"}}
{:value "2", :text {:type :plain_text, :text "Mushrooms"}})}
; Input
[:multi-external-select {:action_id "A123" :max_selected_items 5 :min_query_length 3}
[:placeholder "Pizza Toppings"]
[:option {:value "1"} "Pepperoni"]
[:option {:value "2"} "Mushrooms"]
[:confirm {:confirm "Ok!" :deny "Nah!" :title "You sure?!?!?"}
[:text "This is irreversible!"]]]
; Output
{:action_id "A123",
:max_selected_items 5,
:min_query_length 3,
:type :multi_external_select,
:confirm
{:confirm {:type :plain_text, :text "Ok!", :emoji true},
:deny {:type :plain_text, :text "Nah!", :emoji true},
:title {:type :plain_text, :text "You sure?!?!?", :emoji true},
:text {:type :plain_text, :text "This is irreversible!"},
:style :primary},
:placeholder {:type :plain_text, :text "Pizza Toppings", :emoji true},
:initial_options
({:value "1", :text {:type :plain_text, :text "Pepperoni"}}
{:value "2", :text {:type :plain_text, :text "Mushrooms"}})}
Renders a users multi select element.
Props
(thlack.surfs.repl/props :multi-users-select)
Children
Child | Required | Description |
---|---|---|
placeholder | * | |
confirm |
Usage
; Input
[:multi-users-select {:action_id "A123" :max_selected_items 3 :initial_users ["U123" "U456"]}
[:placeholder "Team captains"]]
; Output
{:action_id "A123",
:max_selected_items 3,
:initial_users ["U123" "U456"],
:type :multi_users_select,
:placeholder {:type :plain_text, :text "Team captains", :emoji true}}
; Input
[:multi-users-select {:action_id "A123" :max_selected_items 3 :initial_users ["U123" "U456"]}
[:placeholder "Team captains"]
[:confirm {:confirm "Ok!" :deny "Nah!" :title "You sure?!?!?"}
[:text "This is irreversible!"]]]
; Output
{:action_id "A123",
:max_selected_items 3,
:initial_users ["U123" "U456"],
:type :multi_users_select,
:confirm
{:confirm {:type :plain_text, :text "Ok!", :emoji true},
:deny {:type :plain_text, :text "Nah!", :emoji true},
:title {:type :plain_text, :text "You sure?!?!?", :emoji true},
:text {:type :plain_text, :text "This is irreversible!"},
:style :primary},
:placeholder {:type :plain_text, :text "Team captains", :emoji true}}
Renders a conversation multi select element.
Props
(thlack.surfs.repl/props :multi-conversations-select)
Children
Child | Required | Description |
---|---|---|
placeholder | * | |
confirm |
Usage
; Input
[:multi-conversations-select {:action_id "A123"
:max_selected_items 3
:default_to_current_conversation true
:initial_conversations ["C123" "C456"]
:filter {:include #{:private}
:exclude_bot_users true
:exclude_external_shared_channels true}}
[:placeholder "Select conversation"]]
; Output
{:action_id "A123",
:max_selected_items 3,
:default_to_current_conversation true,
:initial_conversations ["C123" "C456"],
:filter {:include #{:private}, :exclude_bot_users true, :exclude_external_shared_channels true},
:type :multi_conversations_select,
:placeholder {:type :plain_text, :text "Select conversation", :emoji true}}
; Input
[:multi-conversations-select {:action_id "A123"
:max_selected_items 3
:default_to_current_conversation true
:initial_conversations ["C123" "C456"]
:filter {:include #{:private}
:exclude_bot_users true
:exclude_external_shared_channels true}}
[:placeholder "Select conversation"]
[:confirm {:confirm "Ok!" :deny "Nah!" :title "You sure?!?!?"}
[:text "This is irreversible!"]]]
; Output
{:action_id "A123",
:max_selected_items 3,
:default_to_current_conversation true,
:initial_conversations ["C123" "C456"],
:filter {:include #{:private}, :exclude_bot_users true, :exclude_external_shared_channels true},
:type :multi_conversations_select,
:confirm
{:confirm {:type :plain_text, :text "Ok!", :emoji true},
:deny {:type :plain_text, :text "Nah!", :emoji true},
:title {:type :plain_text, :text "You sure?!?!?", :emoji true},
:text {:type :plain_text, :text "This is irreversible!"},
:style :primary},
:placeholder {:type :plain_text, :text "Select conversation", :emoji true}}
Renders a channel multi select element
Props
(thlack.surfs.repl/props :multi-channels-select)
Children
Child | Required | Description |
---|---|---|
placeholder | * | |
confirm |
Usage
; Input
[:multi-channels-select {:action_id "A123" :max_selected_items 3 :initial_channels ["C123" "C456"]}
[:placeholder "Select channel"]]
; Output
{:action_id "A123",
:max_selected_items 3,
:initial_channels ["C123" "C456"],
:type :multi_channels_select,
:placeholder {:type :plain_text, :text "Select channel", :emoji true}}
; Input
[:multi-channels-select {:action_id "A123" :max_selected_items 3 :initial_channels ["C123" "C456"]}
[:placeholder "Select channel"]
[:confirm {:confirm "Ok!" :deny "Nah!" :title "You sure?!?!?"}
[:text "This is irreversible!"]]]
; Output
{:action_id "A123",
:max_selected_items 3,
:initial_channels ["C123" "C456"],
:type :multi_channels_select,
:confirm
{:confirm {:type :plain_text, :text "Ok!", :emoji true},
:deny {:type :plain_text, :text "Nah!", :emoji true},
:title {:type :plain_text, :text "You sure?!?!?", :emoji true},
:text {:type :plain_text, :text "This is irreversible!"},
:style :primary},
:placeholder {:type :plain_text, :text "Select channel", :emoji true}}
Renders an overflow menu element.
Props
(thlack.surfs.repl/props :overflow)
The :overflow
component can safely omit the :action_id
prop (and thus all props). If :action_id
is not provided, a uuid string will be generated. This simplifies cases where the overflow action_id may be ignored - as is the case with overflow menus containing only urls.
Children
Child | Required | Description |
---|---|---|
option | * | |
confirm |
Usage
; Input
[:overflow {:action_id "A123"}
[:option {:value "1" :url "https://google.com"} "Google"]
[:option {:value "2" :url "https://bing.com"} "Bing"]
[:option {:value "3" :url "https://duckduckgo.com"} "DuckDuckGo"]]
; Output
{:action_id "A123",
:type :overflow,
:options
({:value "1", :url "https://google.com", :text {:type :plain_text, :text "Google"}}
{:value "2", :url "https://bing.com", :text {:type :plain_text, :text "Bing"}}
{:value "3", :url "https://duckduckgo.com", :text {:type :plain_text, :text "DuckDuckGo"}})}
; Input
[:overflow {:action_id "A123"}
[:option {:value "1" :url "https://google.com"} "Google"]
[:option {:value "2" :url "https://bing.com"} "Bing"]
[:option {:value "3" :url "https://duckduckgo.com"} "DuckDuckGo"]
[:confirm {:confirm "Ok!" :deny "Nah!" :title "You sure?!?!?"}
[:text "This is irreversible!"]]]
; Output
{:action_id "A123",
:type :overflow,
:confirm
{:confirm {:type :plain_text, :text "Ok!", :emoji true},
:deny {:type :plain_text, :text "Nah!", :emoji true},
:title {:type :plain_text, :text "You sure?!?!?", :emoji true},
:text {:type :plain_text, :text "This is irreversible!"},
:style :primary},
:options
({:value "1", :url "https://google.com", :text {:type :plain_text, :text "Google"}}
{:value "2", :url "https://bing.com", :text {:type :plain_text, :text "Bing"}}
{:value "3", :url "https://duckduckgo.com", :text {:type :plain_text, :text "DuckDuckGo"}})}
; Input
[:overflow
[:option {:value "1" :url "https://google.com"} "Google"]
[:option {:value "2" :url "https://bing.com"} "Bing"]
[:option {:value "3" :url "https://duckduckgo.com"} "DuckDuckGo"]]
; Output
{:type :overflow,
:action_id "32adf1df-4eff-4cbd-9c76-d60b0fe1a7b8",
:options
({:value "1", :url "https://google.com", :text {:type :plain_text, :text "Google"}}
{:value "2", :url "https://bing.com", :text {:type :plain_text, :text "Bing"}}
{:value "3", :url "https://duckduckgo.com", :text {:type :plain_text, :text "DuckDuckGo"}})}
Renders a plain-text input element.
Props
(thlack.surfs.repl/props :plain-text-input)
Children
Child | Required | Description |
---|---|---|
placeholder | * |
Usage
; Input
[:plain-text-input {:action_id "A123"
:initial_value "hello"
:multiline true
:min_length 1
:max_length 100
:dispatch_action_config {:trigger_actions_on [:on_enter_pressed]}}
[:placeholder "Greeting"]]
; Output
{:action_id "A123",
:initial_value "hello",
:multiline true,
:min_length 1,
:max_length 100,
:dispatch_action_config {:trigger_actions_on [:on_enter_pressed]},
:type :plain_text_input,
:placeholder {:type :plain_text, :text "Greeting", :emoji true}}
Renders a radio button group element.
Props
(thlack.surfs.repl/props :radio-buttons)
Children
Child | Required | Description |
---|---|---|
option | * | |
confirm |
Usage
; Input
[:radio-buttons {:action_id "A123"}
[:option {:value "1"} "Pepperoni"]
[:option {:value "2" :selected? true} "Pineapple"]
[:option {:value "3"} "Mushrooms"]]
; Output
{:action_id "A123",
:type :radio_buttons,
:options
({:value "1", :text {:type :plain_text, :text "Pepperoni"}}
{:value "2", :text {:type :plain_text, :text "Pineapple"}}
{:value "3", :text {:type :plain_text, :text "Mushrooms"}}),
:initial_option {:value "2", :text {:type :plain_text, :text "Pineapple"}}}
; Input
[:radio-buttons {:action_id "A123"}
[:option {:value "1"} "Pepperoni"]
[:option {:value "2" :selected? true} "Pineapple"]
[:option {:value "3"} "Mushrooms"]
[:confirm {:confirm "Ok!" :deny "Nah!" :title "You sure?!?!?"}
[:text "This is irreversible!"]]]
; Output
{:action_id "A123",
:type :radio_buttons,
:confirm
{:confirm {:type :plain_text, :text "Ok!", :emoji true},
:deny {:type :plain_text, :text "Nah!", :emoji true},
:title {:type :plain_text, :text "You sure?!?!?", :emoji true},
:text {:type :plain_text, :text "This is irreversible!"},
:style :primary},
:options
({:value "1", :text {:type :plain_text, :text "Pepperoni"}}
{:value "2", :text {:type :plain_text, :text "Pineapple"}}
{:value "3", :text {:type :plain_text, :text "Mushrooms"}}),
:initial_option {:value "2", :text {:type :plain_text, :text "Pineapple"}}}
Renders a static select element.
Props
(thlack.surfs.repl/props :static-select)
Children
Child | Required | Description |
---|---|---|
placeholder | * | |
option-group | Required if not using :option | |
option | Required if not using :option-group | |
confirm |
Usage
; Input
[:static-select {:action_id "A123"}
[:placeholder "Pizza Topping"]
[:option {:value "1"} "Mushrooms"]
[:option {:value "2" :selected? true} "Pepperoni"]
[:option {:value "3"} "Cheese"]]
; Output
{:action_id "A123",
:type :static_select,
:options
({:value "1", :text {:type :plain_text, :text "Mushrooms"}}
{:value "2", :text {:type :plain_text, :text "Pepperoni"}}
{:value "3", :text {:type :plain_text, :text "Cheese"}}),
:placeholder {:type :plain_text, :text "Pizza Topping", :emoji true},
:initial_option
{:value "2", :text {:type :plain_text, :text "Pepperoni"}}}
; Input
[:static-select {:action_id "A123"}
[:placeholder "Pizza Topping"]
[:option-group
[:label "Veggies"]
[:option {:value "1"} "Mushrooms"]
[:option {:value "2" :selected? true} "Peppers"]]
[:option-group
[:label "Meats"]
[:option {:value "3"} "Pepperoni"]
[:option {:value "4"} "Ham"]]]
; Output
{:action_id "A123",
:type :static_select,
:option_groups
({:label {:type :plain_text, :text "Veggies", :emoji true},
:options
[{:value "1", :text {:type :plain_text, :text "Mushrooms"}}
{:value "2", :text {:type :plain_text, :text "Peppers"}}]}
{:label {:type :plain_text, :text "Meats", :emoji true},
:options
[{:value "3", :text {:type :plain_text, :text "Pepperoni"}}
{:value "4", :text {:type :plain_text, :text "Ham"}}]}),
:placeholder {:type :plain_text, :text "Pizza Topping", :emoji true},
:initial_option
{:value "2", :text {:type :plain_text, :text "Peppers"}}}
; Input
[:static-select {:action_id "A123"}
[:placeholder "Pizza Topping"]
[:option {:value "1"} "Mushrooms"]
[:option {:value "2" :selected? true} "Pepperoni"]
[:option {:value "3"} "Cheese"]
[:confirm {:confirm "Ok!" :deny "Nah!" :title "You sure?!?!?"}
[:text "This is irreversible!"]]]
; Output
{:action_id "A123",
:type :static_select,
:confirm
{:confirm {:type :plain_text, :text "Ok!", :emoji true},
:deny {:type :plain_text, :text "Nah!", :emoji true},
:title {:type :plain_text, :text "You sure?!?!?", :emoji true},
:text {:type :plain_text, :text "This is irreversible!"},
:style :primary},
:options
({:value "1", :text {:type :plain_text, :text "Mushrooms"}}
{:value "2", :text {:type :plain_text, :text "Pepperoni"}}
{:value "3", :text {:type :plain_text, :text "Cheese"}}),
:placeholder {:type :plain_text, :text "Pizza Topping", :emoji true},
:initial_option
{:value "2", :text {:type :plain_text, :text "Pepperoni"}}}
Renders an external select element.
Props
(thlack.surfs.repl/props :external-select)
Children
Child | Required | Description |
---|---|---|
placeholder | * | |
option | Option element is considered initial_option | |
confirm |
Usage
; Input
[:external-select {:action_id "A123" :min_query_length 3}
[:placeholder "Pizza Topping"]
[:option {:value "1"} "Pepperoni"]]
; Output
{:action_id "A123",
:min_query_length 3,
:type :external_select,
:placeholder {:type :plain_text, :text "Pizza Topping", :emoji true},
:initial_option
{:value "1", :text {:type :plain_text, :text "Pepperoni"}}}
; Input
[:external-select {:action_id "A123" :min_query_length 3}
[:placeholder "Pizza Topping"]
[:option {:value "1"} "Pepperoni"]
[:confirm {:confirm "Ok!" :deny "Nah!" :title "You sure?!?!?"}
[:text "This is irreversible!"]]]
; Output
{:action_id "A123",
:min_query_length 3,
:type :external_select,
:confirm
{:confirm {:type :plain_text, :text "Ok!", :emoji true},
:deny {:type :plain_text, :text "Nah!", :emoji true},
:title {:type :plain_text, :text "You sure?!?!?", :emoji true},
:text {:type :plain_text, :text "This is irreversible!"},
:style :primary},
:placeholder {:type :plain_text, :text "Pizza Topping", :emoji true},
:initial_option
{:value "1", :text {:type :plain_text, :text "Pepperoni"}}}
Renders a users select element.
Props
(thlack.surfs.repl/props :users-select)
Children
Child | Required | Description |
---|---|---|
placeholder | * | |
confirm |
Usage
; Input
[:users-select {:action_id "A123" :initial_user "U123"}
[:placeholder "Team captain"]]
; Output
{:action_id "A123",
:initial_user "U123",
:type :users_select,
:placeholder {:type :plain_text, :text "Team captain", :emoji true}}
; Input
[:users-select {:action_id "A123" :initial_user "U123"}
[:placeholder "Team captain"]
[:confirm {:confirm "Ok!" :deny "Nah!" :title "You sure?!?!?"}
[:text "This is irreversible!"]]]
; Output
{:action_id "A123",
:initial_user "U123",
:type :users_select,
:confirm
{:confirm {:type :plain_text, :text "Ok!", :emoji true},
:deny {:type :plain_text, :text "Nah!", :emoji true},
:title {:type :plain_text, :text "You sure?!?!?", :emoji true},
:text {:type :plain_text, :text "This is irreversible!"},
:style :primary},
:placeholder {:type :plain_text, :text "Team captain", :emoji true}}
Renders a conversation select element.
Props
(thlack.surfs.repl/props :conversations-select)
Children
Child | Required | Description |
---|---|---|
placeholder | * | |
confirm |
Usage
; Input
[:conversations-select {:action_id "A123"
:default_to_current_conversation true
:initial_conversation "C123"
:filter {:include #{:private}
:exclude_bot_users true
:exclude_external_shared_channels true}}
[:placeholder "Select conversation"]]
; Output
{:action_id "A123",
:default_to_current_conversation true,
:initial_conversation "C123",
:filter {:include #{:private}, :exclude_bot_users true, :exclude_external_shared_channels true},
:type :conversations_select,
:placeholder {:type :plain_text, :text "Select conversation", :emoji true}}
; Input
[:conversations-select {:action_id "A123"
:default_to_current_conversation true
:initial_conversation "C123"
:filter {:include #{:private}
:exclude_bot_users true
:exclude_external_shared_channels true}}
[:placeholder "Select conversation"]
[:confirm {:confirm "Ok!" :deny "Nah!" :title "You sure?!?!?"}
[:text "This is irreversible!"]]]
; Output
{:action_id "A123",
:default_to_current_conversation true,
:initial_conversation "C123",
:filter {:include #{:private}, :exclude_bot_users true, :exclude_external_shared_channels true},
:type :conversations_select,
:confirm
{:confirm {:type :plain_text, :text "Ok!", :emoji true},
:deny {:type :plain_text, :text "Nah!", :emoji true},
:title {:type :plain_text, :text "You sure?!?!?", :emoji true},
:text {:type :plain_text, :text "This is irreversible!"},
:style :primary},
:placeholder {:type :plain_text, :text "Select conversation", :emoji true}}
Renders a channel select element
Props
(thlack.surfs.repl/props :channels-select)
Children
Child | Required | Description |
---|---|---|
placeholder | * | |
confirm |
Usage
; Input
[:channels-select {:action_id "A123" :initial_channel "C123"]}
[:placeholder "Select channel"]]
; Output
{:action_id "A123",
:initial_channel "C123",
:type :channels_select,
:placeholder {:type :plain_text, :text "Select channel", :emoji true}}
; Input
[:channels-select {:action_id "A123" :initial_channel "C123"}
[:placeholder "Select channel"]
[:confirm {:confirm "Ok!" :deny "Nah!" :title "You sure?!?!?"}
[:text "This is irreversible!"]]]
; Output
{:action_id "A123",
:initial_channel "C123",
:type :channels_select,
:confirm
{:confirm {:type :plain_text, :text "Ok!", :emoji true},
:deny {:type :plain_text, :text "Nah!", :emoji true},
:title {:type :plain_text, :text "You sure?!?!?", :emoji true},
:text {:type :plain_text, :text "This is irreversible!"},
:style :primary},
:placeholder {:type :plain_text, :text "Select channel", :emoji true}}
Renders a time picker element.
Props
(thlack.surfs.repl/props :timepicker)
Children
Child | Required | Description |
---|---|---|
placeholder | ||
confirm |
Usage
; Input
[:timepicker {:action_id "A123" :initial_time "12:30"}
[:placeholder "The time"]]
; Output
{:action_id "A123",
:initial_time "12:30",
:type :timepicker,
:placeholder {:type :plain_text, :text "The time", :emoji true}}
; Input
[:timepicker {:action_id "A123" :initial_time "12:30"}
[:placeholder "The time"]
[:confirm {:confirm "Ok!" :deny "Nah!" :title "You sure?!?!?"}
[:text "This is irreversible!"]]]
; Output
{:action_id "A123",
:initial_time "12:30",
:type :timepicker,
:confirm
{:confirm {:type :plain_text, :text "Ok!", :emoji true},
:deny {:type :plain_text, :text "Nah!", :emoji true},
:title {:type :plain_text, :text "You sure?!?!?", :emoji true},
:text {:type :plain_text, :text "This is irreversible!"},
:style :primary},
:placeholder {:type :plain_text, :text "The time", :emoji true}}
Slack documenation for layout blocks.
Renders an actions block.
Props
(thlack.surfs.repl/props :actions)
Props for :actions
are optional.
Children
Child | Required | Description |
---|---|---|
elements | * (requires at least one element) | One or more of button, radio-buttons, checkboxes, overflow, datepicker, static-select, external-select, users-select, conversations-select, channels-select, timepicker. |
Usage
; Input
[:actions {:block_id "B123"}
[:radio-buttons {:action_id "A123"}
[:option {:value "1"} "Pepperoni"]
[:option {:value "2" :selected? true} "Pineapple"]
[:option {:value "3"} "Mushrooms"]]
[:channels-select {:action_id "A456" :initial_channel "C123"}
[:placeholder "Select channel"]]]
; Output
{:block_id "B123",
:elements
[{:action_id "A123",
:type :radio_buttons,
:options
({:value "1", :text {:type :plain_text, :text "Pepperoni"}}
{:value "2", :text {:type :plain_text, :text "Pineapple"}}
{:value "3", :text {:type :plain_text, :text "Mushrooms"}}),
:initial_option {:value "2", :text {:type :plain_text, :text "Pineapple"}}}
{:action_id "A456",
:initial_channel "C123",
:type :channels_select,
:placeholder {:type :plain_text, :text "Select channel", :emoji true}}],
:type :actions}
; Input
[:actions
[:radio-buttons {:action_id "A123"}
[:option {:value "1"} "Pepperoni"]
[:option {:value "2" :selected? true} "Pineapple"]
[:option {:value "3"} "Mushrooms"]]
[:channels-select {:action_id "A456" :initial_channel "C123"}
[:placeholder "Select channel"]]]
; Output
{:elements
[{:action_id "A123",
:type :radio_buttons,
:options
({:value "1", :text {:type :plain_text, :text "Pepperoni"}}
{:value "2", :text {:type :plain_text, :text "Pineapple"}}
{:value "3", :text {:type :plain_text, :text "Mushrooms"}}),
:initial_option {:value "2", :text {:type :plain_text, :text "Pineapple"}}}
{:action_id "A456",
:initial_channel "C123",
:type :channels_select,
:placeholder {:type :plain_text, :text "Select channel", :emoji true}}],
:type :actions}
Renders a context block.
Props
(thlack.surfs.repl/props :context)
Props for :context
are optional.
Children
Child | Required | Description |
---|---|---|
elements | * (requires at least one element) | One or more of img or text. |
Usage
; Input
[:context {:block_id "B123"}
[:image {:alt_text "It's Bill" :image_url "http://www.fillmurray.com/200/300"}]
[:text "This is some text"]]
; Output
{:block_id "B123",
:elements
[{:alt_text "It's Bill", :image_url "http://www.fillmurray.com/200/300", :type :image}
{:type :plain_text, :text "This is some text"}],
:type :context}
; Input
[:context
[:image {:alt_text "It's Bill" :image_url "http://www.fillmurray.com/200/300"}]
[:text "This is some text"]]
; Output
{:elements
[{:alt_text "It's Bill", :image_url "http://www.fillmurray.com/200/300", :type :image}
{:type :plain_text, :text "This is some text"}],
:type :context}
Renders a divider block.
Props
(thlack.surfs.repl/props :divider)
Props for :divider
are optional.
Usage
; Input
[:divider {:block_id "B123"}]
; Output
{:block_id "B123", :type :divider}
Renders a header block.
Props
(thlack.surfs.repl/props :header)
Props for :header
are optional.
Children
Child | Required | Description |
---|---|---|
text | * | Can be a text component or a string literal. |
Usage
; Input
[:header {:block_id "B123"} "Hello"]
; Output
{:block_id "B123", :type :header, :text {:type :plain_text, :text "Hello"}}
; Input
[:header "Hello"]
; Output
{:type :header, :text {:type :plain_text, :text "Hello"}}
Renders an image block.
Props
(thlack.surfs.repl/props :image)
Children
Child | Required | Description |
---|---|---|
title | Can be a component that resolves to plain-text or a string literal |
Usage
; Input
[:image {:image_url "http://www.fillmurray.com/200/300"
:alt_text "It's Bill"
:block_id "B123"}
[:title "Wowzers!"]]
; Output
{:image_url "http://www.fillmurray.com/200/300",
:alt_text "It's Bill",
:block_id "B123",
:type :image,
:title {:type :plain_text, :text "Wowzers!", :emoji true}}
Renders an input block.
Props
(thlack.surfs.repl/props :input)
Props for :input
are optional.
Children
The input
block contains multiple plain-text children that would make it conceptually difficult to organize them by spec. As such, the input
block always assumes the first child is a plain-text component used for the label. The order of the hint and element components does not matter.
Child | Required | Description |
---|---|---|
label | * | Can be a component that resolves to plain-text or a string literal. Must be the first child. |
hint | Must explicitly be a component that resolves to plain-text. | |
element | * | One of radio-buttons, checkboxes, datepicker, static-select, external-select, users-select, conversations-select, channels-select, multi-static-select, multi-external-select, multi-users-select, multi-conversations-select, multi-channels-select, timepicker. |
Usage
; Input
[:input {:block_id "B123" :dispatch_action false :optional false}
[:label "Some input"]
[:hint "Do something radical"]
[:plain-text-input {:action_id "A123"
:initial_value "hello"}
[:placeholder "Greeting"]]]
; Output
{:block_id "B123",
:dispatch_action false,
:optional false,
:type :input,
:label {:type :plain_text, :text "Some input", :emoji true},
:element
{:action_id "A123",
:initial_value "hello",
:type :plain_text_input,
:placeholder {:type :plain_text, :text "Greeting", :emoji true}},
:hint {:type :plain_text, :text "Do something radical", :emoji true}}
; Input
[:input
[:label "Some input"]
[:hint "Do something radical"]
[:plain-text-input {:action_id "A123"
:initial_value "hello"}
[:placeholder "Greeting"]]]
; Output
{:type :input,
:label {:type :plain_text, :text "Some input", :emoji true},
:element
{:action_id "A123",
:initial_value "hello",
:type :plain_text_input,
:placeholder {:type :plain_text, :text "Greeting", :emoji true}},
:hint {:type :plain_text, :text "Do something radical", :emoji true}}
Renders a section block.
Props
(thlack.surfs.repl/props :section)
Props for :section
are optional.
Children
Child | Required | Description |
---|---|---|
text | * | Text is required if fields is absent. |
fields | * | Fields is required if text is absent. |
accessory | One of button, checkboxes, datepicker, img, static-select, external-select, users-select, conversations-select, channels-select, multi-static-select, multi-external-select, multi-users-select, multi-conversations-select, multi-channels-select, timepicker, overflow, or radio-buttons. |
text
and fields
can be used simultaneously.Usage
; Input
[:section {:block_id "B123"}
[:text "A section"]]
; Output
{:block_id "B123", :type :section, :text {:type :plain_text, :text "A section"}}
; Input
[:section
[:text "A section"]]
; Output
{:type :section, :text {:type :plain_text, :text "A section"}}
; Input
[:section {:block_id "B123"}
[:fields
[:markdown "# Field 1"]
[:plain-text "Field 2"]]]
; Output
{:block_id "B123",
:type :section,
:fields [{:type :mrkdwn, :text "# Field 1", :verbatim false} {:type :plain_text, :text "Field 2", :emoji true}]}
; Input
[:section {:block_id "B123"}
[:text "A section"]
[:datepicker {:action_id "A123" :initial_date "2020-11-30"}
[:placeholder "The date"]]]
; Output
{:block_id "B123",
:type :section,
:text {:type :plain_text, :text "A section"},
:accessory
{:action_id "A123",
:initial_date "2020-11-30",
:type :datepicker,
:placeholder {:type :plain_text, :text "The date", :emoji true}}}
; Input
[:section {:block_id "B123"}
[:fields
[:markdown "# Field 1"]
[:plain-text "Field 2"]]
[:datepicker {:action_id "A123" :initial_date "2020-11-30"}
[:placeholder "The date"]]]
; Output
{:block_id "B123",
:type :section,
:fields [{:type :mrkdwn, :text "# Field 1", :verbatim false} {:type :plain_text, :text "Field 2", :emoji true}],
:accessory
{:action_id "A123",
:initial_date "2020-11-30",
:type :datepicker,
:placeholder {:type :plain_text, :text "The date", :emoji true}}}
; Input
[:section {:block_id "B123"}
[:text "This is an important item"]
[:fields
[:markdown "# Field 1"]
[:plain-text "Field 2"]]
[:datepicker {:action_id "A123" :initial_date "2020-11-30"}
[:placeholder "The date"]
[:confirm {:confirm "Ok!" :deny "Nah!" :title "You sure?!?!?"}
[:text "This is irreversible!"]]]]
; Output
{:block_id "B123",
:type :section,
:text {:type :plain_text, :text "This is an important item"},
:fields [{:type :mrkdwn, :text "# Field 1", :verbatim false} {:type :plain_text, :text "Field 2", :emoji true}],
:accessory
{:action_id "A123",
:initial_date "2020-11-30",
:type :datepicker,
:confirm
{:confirm {:type :plain_text, :text "Ok!", :emoji true},
:deny {:type :plain_text, :text "Nah!", :emoji true},
:title {:type :plain_text, :text "You sure?!?!?", :emoji true},
:text {:type :plain_text, :text "This is irreversible!"},
:style :primary},
:placeholder {:type :plain_text, :text "The date", :emoji true}}}
Slack documentation for views.
Renders a modal surface.
Props
(thlack.surfs.repl/props :modal)
Children
Child | Required | Description |
---|---|---|
blocks | * (requires at least one block) | One or more of actions, context, divider, header, image, input, or section. |
Usage
; Input
[:modal {:private_metadata {:cool? true}
:title "Cool Modal!"
:close "Nah!"
:submit "Yah!"
:disable_emoji_for #{:title :close :submit}}
[:section {:block_id "B123"}
[:text "Some text"]]]
; Output
{:private_metadata "{:cool? true}",
:title {:type :plain_text, :text "Cool Modal!", :emoji false},
:close {:type :plain_text, :text "Nah!", :emoji false},
:submit {:type :plain_text, :text "Yah!", :emoji false},
:type :modal,
:blocks [{:block_id "B123", :type :section, :text {:type :plain_text, :text "Some text"}}]}
Renders a home tab surface.
Props
(thlack.surfs.repl/props :home)
Children
Child | Required | Description |
---|---|---|
blocks | * (requires at least one block) | One or more of actions, context, divider, header, image, input, or section. |
Usage
; Input
[:home {:private_metadata {:cool? true}}
[:section {:block_id "B123"}
[:text "Some text"]]]
; Output
{:private_metadata "{:cool? true}",
:type :home,
:blocks [{:block_id "B123", :type :section, :text {:type :plain_text, :text "Some text"}}]}
Slack documentation for messages.
Props
(thlack.surfs.repl/props :message)
Children
Child | Required | Description |
---|---|---|
text | * | Can be a text component or a string literal. |
blocks | * (requires at least one block if text omitted) | One or more of actions, context, divider, header, image, input, or section. |
Usage
; Input
[:message {:thread_ts "107"} "Text"]
; Output
{:thread_ts "107", :text "Text"}
; Input
[:message "Just text"]
; Output
{:text "Just text"}
; Input
[:message "Fallback" [:divider]]
; Output
{:text "Fallback", :blocks [{:type :divider}]}
; Input
[:message {:thread_ts "107"} [:divider]]
; Output
{:thread_ts "107", :blocks [{:type :divider}]}
; Input
[:message {:thread_ts "107"} "Fallback" [:divider]]
; Output
{:thread_ts "107", :text "Fallback", :blocks [{:type :divider}]}
The disable_emoji_for
prop can be used to override the default value of true
for plain text :emoji
props.
Example:
[:confirm {:confirm "Ok!"
:deny "Nah!"
:title "This is a title!"
:disable_emoji_for #{:deny}}
[:text "Are you sure?"]]
The selected?
prop is an extension to option composition objects. Any component that supports initial_option
or initial_options
attributes can take advantage of this prop to simplify generating initial options.
; Input
[:static-select {:action_id "A123"}
[:placeholder "Pizza Topping"]
[:option {:value "1"} "Mushrooms"]
[:option {:value "2" :selected? true} "Pepperoni"]
[:option {:value "3"} "Cheese"]]
; Output
{:action_id "A123",
:type :static_select,
:options
({:value "1", :text {:type :plain_text, :text "Mushrooms"}}
{:value "2", :text {:type :plain_text, :text "Pepperoni"}}
{:value "3", :text {:type :plain_text, :text "Cheese"}}),
:placeholder {:type :plain_text, :text "Pizza Topping", :emoji true},
:initial_option
{:value "2", :text {:type :plain_text, :text "Pepperoni"}}}
This should make it easier to avoid repeating oneself while crafting views :)
Views support a private_metadata
prop. This is mostly used for persisting state between views. Thanks to Clojure and edn, Surfs can make this feel pretty natural.
In Surfs, the private_metadata
prop will be serialized to edn - making it possible to use plain Clojure structures :)
; Input
[:home {:private_metadata {:cool? true}}
[:section {:block_id "B123"}
[:text "Some text"]]]
; Output
{:private_metadata "{:cool? true}",
:type :home,
:blocks [{:block_id "B123", :type :section, :text {:type :plain_text, :text "Some text"}}]}
Can you improve this documentation?Edit on GitHub
cljdoc is a website building & hosting documentation for Clojure/Script libraries
× close