Repository: slackapi/python-slack-sdk
Pull request #1140 (2021-11-29 09:01:44)

Add focus_on_load support in Block Kit
## Summary

This pull requset adds the new property "focus_on_load" to the Block Kit elements that support it.

### Category (place an `x` in each of the `[ ]`)

- [ ] **slack_sdk.web.WebClient (sync/async)** (Web API client)
- [ ] **slack_sdk.webhook.WebhookClient (sync/async)** (Incoming Webhook, response_url sender)
- [ ] **slack_sdk.socket_mode** (Socket Mode client)
- [ ] **slack_sdk.signature** (Request Signature Verifier)
- [ ] **slack_sdk.oauth** (OAuth Flow Utilities)
- [x] **slack_sdk.models** (UI component builders)
- [ ] **slack_sdk.scim** (SCIM API client)
- [ ] **slack_sdk.audit_logs** (Audit Logs API client)
- [ ] **slack_sdk.rtm_v2** (RTM client)
- [ ] `/docs-src` (Documents, have you run `./scripts/docs.sh`?)
- [ ] `/docs-src-v2` (Documents, have you run `./scripts/docs-v2.sh`?)
- [ ] `/tutorial` (PythOnBoardingBot tutorial)
- [ ] `tests`/`integration_tests` (Automated tests for this library)

## Requirements (place an `x` in each `[ ]`)

- [x] I've read and understood the [Contributing Guidelines](https://github.com/slackapi/python-slack-sdk/blob/main/.github/contributing.md) and have done my best effort to follow them.
- [x] I've read and agree to the [Code of Conduct](https://slackhq.github.io/code-of-conduct).
- [x] I've run `python3 -m venv .venv && source .venv/bin/activate && ./scripts/run_validation.sh` after making the changes.


codecov[bot]: # [Codecov](https://codecov.io/gh/slackapi/python-slack-sdk/pull/1140?src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=slackapi) Report
> Merging [#1140](https://codecov.io/gh/slackapi/python-slack-sdk/pull/1140?src=pr&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=slackapi) (566dd47) into [main](https://codecov.io/gh/slackapi/python-slack-sdk/commit/2f820aef5f8c0536589378d77d3894d8b1e485b1?el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=slackapi) (2f820ae) will **decrease** coverage by `0.04%`.
> The diff coverage is `100.00%`.

[![Impacted file tree graph](https://codecov.io/gh/slackapi/python-slack-sdk/pull/1140/graphs/tree.svg?width=650&height=150&src=pr&token=F0O7meYmtD&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=slackapi)](https://codecov.io/gh/slackapi/python-slack-sdk/pull/1140?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=slackapi)

```diff
@@            Coverage Diff             @@
##             main    #1140      +/-   ##
==========================================
- Coverage   86.63%   86.59%   -0.05%     
==========================================
  Files         110      110              
  Lines       10754    10755       +1     
==========================================
- Hits         9317     9313       -4     
- Misses       1437     1442       +5     
```


| [Impacted Files](https://codecov.io/gh/slackapi/python-slack-sdk/pull/1140?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=slackapi) | Coverage Δ | |
|---|---|---|
| [slack\_sdk/models/blocks/block\_elements.py](https://codecov.io/gh/slackapi/python-slack-sdk/pull/1140/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=slackapi#diff-c2xhY2tfc2RrL21vZGVscy9ibG9ja3MvYmxvY2tfZWxlbWVudHMucHk=) | `92.77% <100.00%> (+0.25%)` | :arrow_up: |
| [slack\_sdk/socket\_mode/builtin/internals.py](https://codecov.io/gh/slackapi/python-slack-sdk/pull/1140/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=slackapi#diff-c2xhY2tfc2RrL3NvY2tldF9tb2RlL2J1aWx0aW4vaW50ZXJuYWxzLnB5) | `70.22% <0.00%> (-1.78%)` | :arrow_down: |
| [slack\_sdk/socket\_mode/websocket\_client/\_\_init\_\_.py](https://codecov.io/gh/slackapi/python-slack-sdk/pull/1140/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=slackapi#diff-c2xhY2tfc2RrL3NvY2tldF9tb2RlL3dlYnNvY2tldF9jbGllbnQvX19pbml0X18ucHk=) | `84.17% <0.00%> (-1.44%)` | :arrow_down: |

------

[Continue to review full report at Codecov](https://codecov.io/gh/slackapi/python-slack-sdk/pull/1140?src=pr&el=continue&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=slackapi).
> **Legend** - [Click here to learn more](https://docs.codecov.io/docs/codecov-delta?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=slackapi)
> `Δ = absolute <relative> (impact)`, `ø = not affected`, `? = missing data`
> Powered by [Codecov](https://codecov.io/gh/slackapi/python-slack-sdk/pull/1140?src=pr&el=footer&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=slackapi). Last update [2f820ae...566dd47](https://codecov.io/gh/slackapi/python-slack-sdk/pull/1140?src=pr&el=lastupdated&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=slackapi). Read the [comment docs](https://docs.codecov.io/docs/pull-request-comments?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=slackapi).

filmaj: @srajiang good question! It seems like something in the most recent commits on `main`, between when the last tag was released and the current `main` HEAD, contributed to at least the `slack_sdk/socket_mode/websocket_client/__init__.py` coverage drop - but that doesnt explain the internals drop in coverage, esp. since the changes mostly look to be documentation 😬 
seratch: Thanks for the reviews. Yeah, I have observed this kind of unexpected coverage drop a few times in the past 🤷 

Patch:
diff --git a/slack_sdk/models/blocks/block_elements.py b/slack_sdk/models/blocks/block_elements.py
index cc9922b..039d5fd 100644
--- a/slack_sdk/models/blocks/block_elements.py
+++ b/slack_sdk/models/blocks/block_elements.py
@@ -176,7 +176,7 @@ class InteractiveElement(BlockElement):
 class InputInteractiveElement(InteractiveElement, metaclass=ABCMeta):
     placeholder_max_length = 150
 
-    attributes = {"type", "action_id", "placeholder", "confirm"}
+    attributes = {"type", "action_id", "placeholder", "confirm", "focus_on_load"}
 
     @property
     def subtype(self) -> Optional[str]:
@@ -190,6 +190,7 @@ class InputInteractiveElement(InteractiveElement, metaclass=ABCMeta):
         type: Optional[str] = None,  # skipcq: PYL-W0622
         subtype: Optional[str] = None,
         confirm: Optional[Union[dict, ConfirmObject]] = None,
+        focus_on_load: Optional[bool] = None,
         **others: dict,
     ):
         """InteractiveElement that is usable in input blocks
@@ -206,6 +207,7 @@ class InputInteractiveElement(InteractiveElement, metaclass=ABCMeta):
 
         self.placeholder = TextObject.parse(placeholder)
         self.confirm = ConfirmObject.parse(confirm)
+        self.focus_on_load = focus_on_load
 
     @JsonValidator(
         f"placeholder attribute cannot exceed {placeholder_max_length} characters"
@@ -365,6 +367,7 @@ class CheckboxesElement(InputInteractiveElement):
         options: Optional[Sequence[Union[dict, Option]]] = None,
         initial_options: Optional[Sequence[Union[dict, Option]]] = None,
         confirm: Optional[Union[dict, ConfirmObject]] = None,
+        focus_on_load: Optional[bool] = None,
         **others: dict,
     ):
         """A checkbox group that allows a user to choose multiple items from a list of possible options.
@@ -380,11 +383,14 @@ class CheckboxesElement(InputInteractiveElement):
                 These options will be selected when the checkbox group initially loads.
             confirm: A confirm object that defines an optional confirmation dialog that appears
                 after clicking one of the checkboxes in this element.
+            focus_on_load: Indicates whether the element will be set to auto focus within the view object.
+                Only one element can be set to true. Defaults to false.
         """
         super().__init__(
             type=self.type,
             action_id=action_id,
             confirm=ConfirmObject.parse(confirm),
+            focus_on_load=focus_on_load,
         )
         show_unknown_key_warning(self, others)
 
@@ -411,6 +417,7 @@ class DatePickerElement(InputInteractiveElement):
         placeholder: Optional[Union[str, dict, TextObject]] = None,
         initial_date: Optional[str] = None,
         confirm: Optional[Union[dict, ConfirmObject]] = None,
+        focus_on_load: Optional[bool] = None,
         **others: dict,
     ):
         """
@@ -429,12 +436,15 @@ class DatePickerElement(InputInteractiveElement):
                 This should be in the format YYYY-MM-DD.
             confirm: A confirm object that defines an optional confirmation dialog
                 that appears after a date is selected.
+            focus_on_load: Indicates whether the element will be set to auto focus within the view object.
+                Only one element can be set to true. Defaults to false.
         """
         super().__init__(
             type=self.type,
             action_id=action_id,
             placeholder=TextObject.parse(placeholder, PlainTextObject.type),
             confirm=ConfirmObject.parse(confirm),
+            focus_on_load=focus_on_load,
         )
         show_unknown_key_warning(self, others)
 
@@ -470,6 +480,7 @@ class TimePickerElement(InputInteractiveElement):
         placeholder: Optional[Union[str, dict, TextObject]] = None,
         initial_time: Optional[str] = None,
         confirm: Optional[Union[dict, ConfirmObject]] = None,
+        focus_on_load: Optional[bool] = None,
         **others: dict,
     ):
         """
@@ -491,12 +502,15 @@ class TimePickerElement(InputInteractiveElement):
                 and mm is minutes with leading zeros (00 to 59), for example 22:25 for 10:25pm.
             confirm: A confirm object that defines an optional confirmation dialog
                 that appears after a time is selected.
+            focus_on_load: Indicates whether the element will be set to auto focus within the view object.
+                Only one element can be set to true. Defaults to false.
         """
         super().__init__(
             type=self.type,
             action_id=action_id,
             placeholder=TextObject.parse(placeholder, PlainTextObject.type),
             confirm=ConfirmObject.parse(confirm),
+            focus_on_load=focus_on_load,
         )
         show_unknown_key_warning(self, others)
 
@@ -581,6 +595,7 @@ class StaticSelectElement(InputInteractiveElement):
         option_groups: Optional[Sequence[Union[dict, OptionGroup]]] = None,
         initial_option: Optional[Union[dict, Option]] = None,
         confirm: Optional[Union[dict, ConfirmObject]] = None,
+        focus_on_load: Optional[bool] = None,
         **others: dict,
     ):
         """This is the simplest form of select menu, with a static list of options passed in when defining the element.
@@ -603,12 +618,15 @@ class StaticSelectElement(InputInteractiveElement):
                 This option will be selected when the menu initially loads.
             confirm: A confirm object that defines an optional confirmation dialog
                 that appears after a menu item is selected.
+            focus_on_load: Indicates whether the element will be set to auto focus within the view object.
+                Only one element can be set to true. Defaults to false.
         """
         super().__init__(
             type=self.type,
             action_id=action_id,
             placeholder=TextObject.parse(placeholder, PlainTextObject.type),
             confirm=ConfirmObject.parse(confirm),
+            focus_on_load=focus_on_load,
         )
         show_unknown_key_warning(self, others)
 
@@ -659,6 +677,7 @@ class StaticMultiSelectElement(InputInteractiveElement):
         initial_options: Optional[Sequence[Option]] = None,
         confirm: Optional[Union[dict, ConfirmObject]] = None,
         max_selected_items: Optional[int] = None,
+        focus_on_load: Optional[bool] = None,
         **others: dict,
     ):
         """
@@ -684,12 +703,15 @@ class StaticMultiSelectElement(InputInteractiveElement):
                 that appears before the multi-select choices are submitted.
             max_selected_items: Specifies the maximum number of items that can be selected in the menu.
                 Minimum number is 1.
+            focus_on_load: Indicates whether the element will be set to auto focus within the view object.
+                Only one element can be set to true. Defaults to false.
         """
         super().__init__(
             type=self.type,
             action_id=action_id,
             placeholder=TextObject.parse(placeholder, PlainTextObject.type),
             confirm=ConfirmObject.parse(confirm),
+            focus_on_load=focus_on_load,
         )
         show_unknown_key_warning(self, others)
 
@@ -739,6 +761,7 @@ class SelectElement(InputInteractiveElement):
         option_groups: Optional[Sequence[OptionGroup]] = None,
         initial_option: Optional[Option] = None,
         confirm: Optional[Union[dict, ConfirmObject]] = None,
+        focus_on_load: Optional[bool] = None,
         **others: dict,
     ):
         """This is the simplest form of select menu, with a static list of options passed in when defining the element.
@@ -761,12 +784,15 @@ class SelectElement(InputInteractiveElement):
                 This option will be selected when the menu initially loads.
             confirm: A confirm object that defines an optional confirmation dialog
                 that appears after a menu item is selected.
+            focus_on_load: Indicates whether the element will be set to auto focus within the view object.
+                Only one element can be set to true. Defaults to false.
         """
         super().__init__(
             type=self.type,
             action_id=action_id,
             placeholder=TextObject.parse(placeholder, PlainTextObject.type),
             confirm=ConfirmObject.parse(confirm),
+            focus_on_load=focus_on_load,
         )
         show_unknown_key_warning(self, others)
 
@@ -816,6 +842,7 @@ class ExternalDataSelectElement(InputInteractiveElement):
         initial_option: Union[Optional[Option], Optional[OptionGroup]] = None,
         min_query_length: Optional[int] = None,
         confirm: Optional[Union[dict, ConfirmObject]] = None,
+        focus_on_load: Optional[bool] = None,
         **others: dict,
     ):
         """
@@ -840,12 +867,15 @@ class ExternalDataSelectElement(InputInteractiveElement):
                 The default value is 3.
             confirm: A confirm object that defines an optional confirmation dialog
                 that appears after a menu item is selected.
+            focus_on_load: Indicates whether the element will be set to auto focus within the view object.
+                Only one element can be set to true. Defaults to false.
         """
         super().__init__(
             type=self.type,
             action_id=action_id,
             placeholder=TextObject.parse(placeholder, PlainTextObject.type),
             confirm=ConfirmObject.parse(confirm),
+            focus_on_load=focus_on_load,
         )
         show_unknown_key_warning(self, others)
 
@@ -871,6 +901,7 @@ class ExternalDataMultiSelectElement(InputInteractiveElement):
         initial_options: Optional[Sequence[Union[dict, Option]]] = None,
         confirm: Optional[Union[dict, ConfirmObject]] = None,
         max_selected_items: Optional[int] = None,
+        focus_on_load: Optional[bool] = None,
         **others: dict,
     ):
         """
@@ -896,12 +927,15 @@ class ExternalDataMultiSelectElement(InputInteractiveElement):
                 before the multi-select choices are submitted.
             max_selected_items: Specifies the maximum number of items that can be selected in the menu.
                 Minimum number is 1.
+            focus_on_load: Indicates whether the element will be set to auto focus within the view object.
+                Only one element can be set to true. Defaults to false.
         """
         super().__init__(
             type=self.type,
             action_id=action_id,
             placeholder=TextObject.parse(placeholder, PlainTextObject.type),
             confirm=ConfirmObject.parse(confirm),
+            focus_on_load=focus_on_load,
         )
         show_unknown_key_warning(self, others)
 
@@ -929,6 +963,7 @@ class UserSelectElement(InputInteractiveElement):
         action_id: Optional[str] = None,
         initial_user: Optional[str] = None,
         confirm: Optional[Union[dict, ConfirmObject]] = None,
+        focus_on_load: Optional[bool] = None,
         **others: dict,
     ):
         """
@@ -946,12 +981,15 @@ class UserSelectElement(InputInteractiveElement):
             initial_user: The user ID of any valid user to be pre-selected when the menu loads.
             confirm: A confirm object that defines an optional confirmation dialog
                 that appears after a menu item is selected.
+            focus_on_load: Indicates whether the element will be set to auto focus within the view object.
+                Only one element can be set to true. Defaults to false.
         """
         super().__init__(
             type=self.type,
             action_id=action_id,
             placeholder=TextObject.parse(placeholder, PlainTextObject.type),
             confirm=ConfirmObject.parse(confirm),
+            focus_on_load=focus_on_load,
         )
         show_unknown_key_warning(self, others)
 
@@ -973,6 +1011,7 @@ class UserMultiSelectElement(InputInteractiveElement):
         initial_users: Optional[Sequence[str]] = None,
         confirm: Optional[Union[dict, ConfirmObject]] = None,
         max_selected_items: Optional[int] = None,
+        focus_on_load: Optional[bool] = None,
         **others: dict,
     ):
         """
@@ -992,12 +1031,15 @@ class UserMultiSelectElement(InputInteractiveElement):
                 before the multi-select choices are submitted.
             max_selected_items: Specifies the maximum number of items that can be selected in the menu.
                 Minimum number is 1.
+            focus_on_load: Indicates whether the element will be set to auto focus within the view object.
+                Only one element can be set to true. Defaults to false.
         """
         super().__init__(
             type=self.type,
             action_id=action_id,
             placeholder=TextObject.parse(placeholder, PlainTextObject.type),
             confirm=ConfirmObject.parse(confirm),
+            focus_on_load=focus_on_load,
         )
         show_unknown_key_warning(self, others)
 
@@ -1078,6 +1120,7 @@ class ConversationSelectElement(InputInteractiveElement):
         response_url_enabled: Optional[bool] = None,
         default_to_current_conversation: Optional[bool] = None,
         filter: Optional[ConversationFilter] = None,  # skipcq: PYL-W0622
+        focus_on_load: Optional[bool] = None,
         **others: dict,
     ):
         """
@@ -1103,12 +1146,15 @@ class ConversationSelectElement(InputInteractiveElement):
             default_to_current_conversation: Pre-populates the select menu with the conversation
                 that the user was viewing when they opened the modal, if available. Default is false.
             filter: A filter object that reduces the list of available conversations using the specified criteria.
+            focus_on_load: Indicates whether the element will be set to auto focus within the view object.
+                Only one element can be set to true. Defaults to false.
         """
         super().__init__(
             type=self.type,
             action_id=action_id,
             placeholder=TextObject.parse(placeholder, PlainTextObject.type),
             confirm=ConfirmObject.parse(confirm),
+            focus_on_load=focus_on_load,
         )
         show_unknown_key_warning(self, others)
 
@@ -1142,6 +1188,7 @@ class ConversationMultiSelectElement(InputInteractiveElement):
         max_selected_items: Optional[int] = None,
         default_to_current_conversation: Optional[bool] = None,
         filter: Optional[Union[dict, ConversationFilter]] = None,  # skipcq: PYL-W0622
+        focus_on_load: Optional[bool] = None,
         **others: dict,
     ):
         """
@@ -1166,12 +1213,15 @@ class ConversationMultiSelectElement(InputInteractiveElement):
             default_to_current_conversation: Pre-populates the select menu with the conversation that
                 the user was viewing when they opened the modal, if available. Default is false.
             filter: A filter object that reduces the list of available conversations using the specified criteria.
+            focus_on_load: Indicates whether the element will be set to auto focus within the view object.
+                Only one element can be set to true. Defaults to false.
         """
         super().__init__(
             type=self.type,
             action_id=action_id,
             placeholder=TextObject.parse(placeholder, PlainTextObject.type),
             confirm=ConfirmObject.parse(confirm),
+            focus_on_load=focus_on_load,
         )
         show_unknown_key_warning(self, others)
 
@@ -1201,6 +1251,7 @@ class ChannelSelectElement(InputInteractiveElement):
         initial_channel: Optional[str] = None,
         confirm: Optional[Union[dict, ConfirmObject]] = None,
         response_url_enabled: Optional[bool] = None,
+        focus_on_load: Optional[bool] = None,
         **others: dict,
     ):
         """
@@ -1222,12 +1273,15 @@ class ChannelSelectElement(InputInteractiveElement):
                 When set to true, the view_submission payload from the menu's parent view will contain a response_url.
                 This response_url can be used for message responses.
                 The target channel for the message will be determined by the value of this select menu
+            focus_on_load: Indicates whether the element will be set to auto focus within the view object.
+                Only one element can be set to true. Defaults to false.
         """
         super().__init__(
             type=self.type,
             action_id=action_id,
             placeholder=TextObject.parse(placeholder, PlainTextObject.type),
             confirm=ConfirmObject.parse(confirm),
+            focus_on_load=focus_on_load,
         )
         show_unknown_key_warning(self, others)
 
@@ -1250,6 +1304,7 @@ class ChannelMultiSelectElement(InputInteractiveElement):
         initial_channels: Optional[Sequence[str]] = None,
         confirm: Optional[Union[dict, ConfirmObject]] = None,
         max_selected_items: Optional[int] = None,
+        focus_on_load: Optional[bool] = None,
         **others: dict,
     ):
         """
@@ -1270,12 +1325,15 @@ class ChannelMultiSelectElement(InputInteractiveElement):
                 before the multi-select choices are submitted.
             max_selected_items: Specifies the maximum number of items that can be selected in the menu.
                 Minimum number is 1.
+            focus_on_load: Indicates whether the element will be set to auto focus within the view object.
+                Only one element can be set to true. Defaults to false.
         """
         super().__init__(
             type=self.type,
             action_id=action_id,
             placeholder=TextObject.parse(placeholder, PlainTextObject.type),
             confirm=ConfirmObject.parse(confirm),
+            focus_on_load=focus_on_load,
         )
         show_unknown_key_warning(self, others)
 
@@ -1313,6 +1371,7 @@ class PlainTextInputElement(InputInteractiveElement):
         min_length: Optional[int] = None,
         max_length: Optional[int] = None,
         dispatch_action_config: Optional[Union[dict, DispatchActionConfig]] = None,
+        focus_on_load: Optional[bool] = None,
         **others: dict,
     ):
         """
@@ -1338,11 +1397,14 @@ class PlainTextInputElement(InputInteractiveElement):
                 they will receive an error.
             dispatch_action_config: A dispatch configuration object that determines when
                 during text input the element returns a block_actions payload.
+            focus_on_load: Indicates whether the element will be set to auto focus within the view object.
+                Only one element can be set to true. Defaults to false.
         """
         super().__init__(
             type=self.type,
             action_id=action_id,
             placeholder=TextObject.parse(placeholder, PlainTextObject.type),
+            focus_on_load=focus_on_load,
         )
         show_unknown_key_warning(self, others)
 
@@ -1372,6 +1434,7 @@ class RadioButtonsElement(InputInteractiveElement):
         options: Optional[Sequence[Union[dict, Option]]] = None,
         initial_option: Optional[Union[dict, Option]] = None,
         confirm: Optional[Union[dict, ConfirmObject]] = None,
+        focus_on_load: Optional[bool] = None,
         **others: dict,
     ):
         """A radio button group that allows a user to choose one item from a list of possible options.
@@ -1387,11 +1450,14 @@ class RadioButtonsElement(InputInteractiveElement):
                 This option will be selected when the radio button group initially loads.
             confirm: A confirm object that defines an optional confirmation dialog that appears
                 after clicking one of the radio buttons in this element.
+            focus_on_load: Indicates whether the element will be set to auto focus within the view object.
+                Only one element can be set to true. Defaults to false.
         """
         super().__init__(
             type=self.type,
             action_id=action_id,
             confirm=ConfirmObject.parse(confirm),
+            focus_on_load=focus_on_load,
         )
         show_unknown_key_warning(self, others)
 


Test patch:
diff --git a/tests/slack_sdk/models/test_elements.py b/tests/slack_sdk/models/test_elements.py
index 7ebb6b5..8da0a9f 100644
--- a/tests/slack_sdk/models/test_elements.py
+++ b/tests/slack_sdk/models/test_elements.py
@@ -59,6 +59,7 @@ class InteractiveElementTests(unittest.TestCase):
             "type": "plain_text_input",
             "action_id": "plain_input",
             "placeholder": {"type": "plain_text", "text": "Enter some plain text"},
+            "focus_on_load": True,
         }
         # Any properties should not be lost
         self.assertDictEqual(input, InputInteractiveElement(**input).to_dict())
@@ -207,6 +208,20 @@ class CheckboxesElementTests(unittest.TestCase):
         }
         self.assertDictEqual(input, CheckboxesElement(**input).to_dict())
 
+    def test_focus_on_load(self):
+        input = {
+            "type": "checkboxes",
+            "action_id": "this_is_an_action_id",
+            "initial_options": [
+                {"value": "A1", "text": {"type": "plain_text", "text": "Checkbox 1"}}
+            ],
+            "options": [
+                {"value": "A1", "text": {"type": "plain_text", "text": "Checkbox 1"}},
+            ],
+            "focus_on_load": True,
+        }
+        self.assertDictEqual(input, CheckboxesElement(**input).to_dict())
+
 
 # -------------------------------------------------
 # DatePicker
@@ -263,6 +278,16 @@ class DatePickerElementTests(unittest.TestCase):
             elem = DatePickerElement(action_id="1", placeholder="12345" * 100)
             elem.to_dict()
 
+    def test_focus_on_load(self):
+        input = {
+            "type": "datepicker",
+            "action_id": "datepicker123",
+            "initial_date": "1990-04-28",
+            "placeholder": {"type": "plain_text", "text": "Select a date"},
+            "focus_on_load": True,
+        }
+        self.assertDictEqual(input, DatePickerElement(**input).to_dict())
+
 
 # -------------------------------------------------
 # TimePicker
@@ -311,6 +336,19 @@ class TimePickerElementTests(unittest.TestCase):
                 initial_time="25:00",
             ).to_dict()
 
+    def test_focus_on_load(self):
+        input = {
+            "type": "timepicker",
+            "action_id": "timepicker123",
+            "initial_time": "11:40",
+            "placeholder": {
+                "type": "plain_text",
+                "text": "Select a time",
+            },
+            "focus_on_load": True,
+        }
+        self.assertDictEqual(input, TimePickerElement(**input).to_dict())
+
 
 # -------------------------------------------------
 # Image
@@ -380,6 +418,30 @@ class StaticMultiSelectElementTests(unittest.TestCase):
         }
         self.assertDictEqual(input, StaticMultiSelectElement(**input).to_dict())
 
+    def test_focus_on_load(self):
+        input = {
+            "action_id": "text1234",
+            "type": "multi_static_select",
+            "placeholder": {"type": "plain_text", "text": "Select items"},
+            "options": [
+                {
+                    "text": {"type": "plain_text", "text": "*this is plain_text text*"},
+                    "value": "value-0",
+                },
+                {
+                    "text": {"type": "plain_text", "text": "*this is plain_text text*"},
+                    "value": "value-1",
+                },
+                {
+                    "text": {"type": "plain_text", "text": "*this is plain_text text*"},
+                    "value": "value-2",
+                },
+            ],
+            "max_selected_items": 1,
+            "focus_on_load": True,
+        }
+        self.assertDictEqual(input, StaticMultiSelectElement(**input).to_dict())
+
 
 class StaticSelectElementTests(unittest.TestCase):
     maxDiff = None
@@ -511,6 +573,21 @@ class StaticSelectElementTests(unittest.TestCase):
                 options=[self.option_one] * 101,
             ).to_dict()
 
+    def test_focus_on_load(self):
+        input = {
+            "action_id": "text1234",
+            "type": "static_select",
+            "placeholder": {"type": "plain_text", "text": "Select an item"},
+            "options": [
+                {
+                    "text": {"type": "plain_text", "text": "*this is plain_text text*"},
+                    "value": "value-0",
+                },
+            ],
+            "focus_on_load": True,
+        }
+        self.assertDictEqual(input, StaticSelectElement(**input).to_dict())
+
 
 # -------------------------------------------------
 # External Data Source Select
@@ -545,6 +622,15 @@ class ExternalDataMultiSelectElementTests(unittest.TestCase):
         }
         self.assertDictEqual(input, ExternalDataMultiSelectElement(**input).to_dict())
 
+    def test_focus_on_load(self):
+        input = {
+            "action_id": "text1234",
+            "type": "multi_external_select",
+            "placeholder": {"type": "plain_text", "text": "Select items"},
+            "focus_on_load": True,
+        }
+        self.assertDictEqual(input, ExternalDataMultiSelectElement(**input).to_dict())
+
 
 class ExternalDataSelectElementTests(unittest.TestCase):
     maxDiff = None
@@ -614,6 +700,15 @@ class ExternalDataSelectElementTests(unittest.TestCase):
             ).to_dict(),
         )
 
+    def test_focus_on_load(self):
+        input = {
+            "action_id": "text1234",
+            "type": "external_select",
+            "placeholder": {"type": "plain_text", "text": "Select an item"},
+            "focus_on_load": True,
+        }
+        self.assertDictEqual(input, ExternalDataSelectElement(**input).to_dict())
+
 
 # -------------------------------------------------
 # Users Select
@@ -661,6 +756,16 @@ class UserSelectElementTests(unittest.TestCase):
             ).to_dict(),
         )
 
+    def test_focus_on_load(self):
+        input = {
+            "action_id": "text1234",
+            "type": "users_select",
+            "placeholder": {"type": "plain_text", "text": "Select an item"},
+            "initial_user": "U123",
+            "focus_on_load": True,
+        }
+        self.assertDictEqual(input, UserSelectElement(**input).to_dict())
+
 
 # -------------------------------------------------
 # Conversations Select
@@ -680,6 +785,16 @@ class ConversationSelectMultiElementTests(unittest.TestCase):
         }
         self.assertDictEqual(input, ConversationMultiSelectElement(**input).to_dict())
 
+    def test_focus_on_load(self):
+        input = {
+            "action_id": "text1234",
+            "type": "multi_conversations_select",
+            "placeholder": {"type": "plain_text", "text": "Select conversations"},
+            "initial_conversations": ["C123", "C234"],
+            "focus_on_load": True,
+        }
+        self.assertDictEqual(input, ConversationMultiSelectElement(**input).to_dict())
+
 
 class ConversationSelectElementTests(unittest.TestCase):
     def test_document(self):
@@ -694,6 +809,16 @@ class ConversationSelectElementTests(unittest.TestCase):
         }
         self.assertDictEqual(input, ConversationSelectElement(**input).to_dict())
 
+    def test_focus_on_load(self):
+        input = {
+            "action_id": "text1234",
+            "type": "conversations_select",
+            "placeholder": {"type": "plain_text", "text": "Select an item"},
+            "initial_conversation": "C123",
+            "focus_on_load": True,
+        }
+        self.assertDictEqual(input, ConversationSelectElement(**input).to_dict())
+
 
 # -------------------------------------------------
 # Channels Select
@@ -711,6 +836,16 @@ class ChannelSelectMultiElementTests(unittest.TestCase):
         }
         self.assertDictEqual(input, ChannelMultiSelectElement(**input).to_dict())
 
+    def test_focus_on_load(self):
+        input = {
+            "action_id": "text1234",
+            "type": "multi_channels_select",
+            "placeholder": {"type": "plain_text", "text": "Select channels"},
+            "initial_channels": ["C123", "C234"],
+            "focus_on_load": True,
+        }
+        self.assertDictEqual(input, ChannelMultiSelectElement(**input).to_dict())
+
 
 class ChannelSelectElementTests(unittest.TestCase):
     def test_document(self):
@@ -723,6 +858,15 @@ class ChannelSelectElementTests(unittest.TestCase):
         }
         self.assertDictEqual(input, ChannelSelectElement(**input).to_dict())
 
+    def test_focus_on_load(self):
+        input = {
+            "action_id": "text1234",
+            "type": "channels_select",
+            "placeholder": {"type": "plain_text", "text": "Select an item"},
+            "focus_on_load": True,
+        }
+        self.assertDictEqual(input, ChannelSelectElement(**input).to_dict())
+
 
 # -------------------------------------------------
 # Overflow Menu Select
@@ -795,6 +939,15 @@ class PlainTextInputElementTests(unittest.TestCase):
         }
         self.assertDictEqual(input, PlainTextInputElement(**input).to_dict())
 
+    def test_focus_on_load(self):
+        input = {
+            "type": "plain_text_input",
+            "action_id": "plain_input",
+            "placeholder": {"type": "plain_text", "text": "Enter some plain text"},
+            "focus_on_load": True,
+        }
+        self.assertDictEqual(input, PlainTextInputElement(**input).to_dict())
+
 
 # -------------------------------------------------
 # Radio Buttons
@@ -814,9 +967,21 @@ class RadioButtonsElementTest(unittest.TestCase):
                 {"value": "A1", "text": {"type": "plain_text", "text": "Radio 1"}},
                 {"value": "A2", "text": {"type": "plain_text", "text": "Radio 2"}},
             ],
+        }
+        self.assertDictEqual(input, RadioButtonsElement(**input).to_dict())
+
+    def test_focus_on_load(self):
+        input = {
+            "type": "radio_buttons",
+            "action_id": "this_is_an_action_id",
             "initial_option": {
-                "value": "A2",
-                "text": {"type": "plain_text", "text": "Radio 2"},
+                "value": "A1",
+                "text": {"type": "plain_text", "text": "Radio 1"},
             },
+            "options": [
+                {"value": "A1", "text": {"type": "plain_text", "text": "Radio 1"}},
+                {"value": "A2", "text": {"type": "plain_text", "text": "Radio 2"}},
+            ],
+            "focus_on_load": True,
         }
         self.assertDictEqual(input, RadioButtonsElement(**input).to_dict())