Search code examples
slackslack-api

When does a block_id need to be updated?


I'm trying to understand the requirements for unique block_ids in a modal. Specifically, this instruction in the field documentation for input blocks:

block_id should be unique for each message and each iteration of a message. If a message is updated, use a new block_id.

Ok, that seems to imply that if I send a views.update call to update a modal in response to some interaction, I need to update all the block_ids with a new unique value. Which is annoying, especially as those same block_ids are the keys for the error response, but whatever.

Except that this seems to directly contradict this note in the "using modals" update docs (and identical notes in the views.update docs and the views reference):

Data entered or selected in input blocks can be preserved while updating views. The new view object that you use with views.update should contain the same input blocks and elements with identical block_id and action_id values.

So I don't need to change the block_id when updating the view? So what does the first note mean - when do I need a new block_id? Or is there some specific significance to "message" there - as opposed to "view" or "surface" maybe - that I'm not getting?

(I guess a sub-question here is, what exactly is the scope of uniqueness for block_ids? We already have the distinction between action_ids, which only need to be unique within a view, and external_ids, which need to be unique across "all views on a team"; is block_id a third category?)


Solution

  • Note: This answer is based on my experience building and running the Simple Poll Slack app. I'm not completely certain what the Slack-approved "most correct" approach is, but I have a pretty good sense of what works in practice.


    The short answer here is that block_ids don't need to be unique in most cases. The majority of our block_ids are not unique. For example, we a have a modal/view in which users can set up a recurring poll. The block_id for this block is set_up_recurring_poll. There is no issue with this block_id not being unique.

    So that's our default approach: Choose non-unique, human-readable names for block_ids. As you mentioned, these are then also the easiest to parse when Slack sends over the block_actions/view_submission payloads.

    In practice, Slack uses the block_id as a way to maintain state within interactive/input blocks. Specifically the block_id uniqueness is used to decide whether to update/replace the block you previously specified with a new block or whether to keep the existing block. Essentially a form of caching.

    That's a bit abstract, so I'm going to give two examples:

    • Updating a surface that has a plain_text_input block
    • Updating a surface that has a static_select menu

    Updating a surface that has a plain_text_input block

    1. Imagine your app opened a view that has a plain_text_input block.
    2. A user enters something into this block, for example "Hello World"
    3. A user then clicks on a button in the view and your app decides to update the view with views.update but keeping that same plain_text_input block in the view

    If in this call to views.update, your app kept the block_id the same as the block_id your app used in step 1, then the "Hello World" the user entered will still be there.

    If in this call to views.update, your app used a different block_id to the one your app used in step 1, then the "Hello World" the user entered is gone and the user will see an empty input field.

    So in this case, if your intention is to clear the plain_text_input, then use a different block_id. If your intention is to maintain the user input, then use the same block_id.

    Updating a surface that has a static_select menu

    1. Imagine your app posted a message that has a static_select menu
    2. A user selects one of the options in the static_select menu
    3. Your app then updates the underlying message (using chat.update). The only change between the previous and updated message is that your app added another option to the static_select menu

    In this case, if the block containing the static_select menu had the same block_id in the updated message, then the new option would not show up in the static_select menu. Slack sees that the block_id is the same as before, and decided not to update the actual content of the block.

    So in this case, if your desire is to add another option to the static_select menu, then you need to use a new block id.

    When we run into a case like this, we tend to append a randomly generated suffix to our existing, human-readable block id. So instead of my-static-select-menu, we'd instead use my-static-select-menu&5jRMA as our block_id. Then later when we parse the block_id we look only at the value before the &


    The overall approach that I would recommend and that has worked for us:

    Default to using non-unique, human-readable block_ids. And if you happen to run into a case, where Slack is caching the block content based on the id and this is preventing you from doing something, then add an at-runtime-generated, random suffix to the block id, which will bust Slack's cache.

    what exactly is the scope of uniqueness for block_ids?

    In my mental model, block_ids need to be unique only in the context of their directly adjacent blocks (ie the array of blocks: []) that any given block_id exists within. Or said another way, they need to be unique for the instance of the surface they are a part of (message, view, app home)

    So you can't have the same block_id twice in the exact same message, view, or app_home page – but it's totally fine to use the same, non-unique block id to for example power the "Upgrade" button in a message. Even if that same message is posted several times


    One final thought: For questions like these and similar, you might also find it useful to send a note to [email protected] – there are several folks on their Customer Success team which are dedicated to answering technical questions like this one. They've helped me in the past!