Using UIKit Blocks

This document covers various examples to help you use the Apps-Engine UI blocks so you can create meaningful user interactions in your apps. The UI blocks are triggered by an action or a condition. In these examples, the UI blocks will be triggered when a message is starred. First, we will see how to create a single block and then we will add more elements to create complex visual layouts.

Let’s create a basic section that contains some text. This will be displayed in a room when a message is starred. The main app class looks like this:

import {
    IAppAccessors, IConfigurationExtend, ILogger, IHttp, IModify, IPersistence, IRead, IMessageBuilder, IMessageRead
} from '@rocket.chat/apps-engine/definition/accessors';
import { App } from '@rocket.chat/apps-engine/definition/App';
import { IAppInfo } from '@rocket.chat/apps-engine/definition/metadata';
import { UIKitInteractionType, IUIKitInteractionHandler, UIKitSurfaceType } from '@rocket.chat/apps-engine/definition/uikit';
import { OpenCtxBarCommand } from './contextbar';
import { uiKitMessage } from '@rocket.chat/ui-kit';
import { IMessage, IMessageStarContext, IPostMessageSent, IPostMessageStarred } from '@rocket.chat/apps-engine/definition/messages';

export class uiblocksApp extends App implements IPostMessageStarred {

    async executePostMessageStarred(context: IMessageStarContext, read: IRead, http: IHttp, persistence: IPersistence, modify: IModify): Promise<void> {
        const messageCreator = modify.getCreator().startMessage();

        messageCreator.setBlocks([
            {
                type: 'section', // the type of block
                text: {
                    type: 'plain_text',
                    text: 'Message starred! :)',
                    emoji: true
                }
            },
        ])
        messageCreator.setRoom(context.message.room);
        await modify.getCreator().finish(messageCreator);
    }
}
TypeScript

Whenever a message is starred, the app bot returns the text message as shown in this screenshot:

In the same example, we are going to add more blocks and elements to demonstrate how you can create complex UI layouts.

async executePostMessageStarred(context: IMessageStarContext, read: IRead, http: IHttp, persistence: IPersistence, modify: IModify): Promise<void> {
        const messageCreator = modify.getCreator().startMessage();

        messageCreator.setBlocks([
            {
                type: 'section', // section block
                text: {
                    type: 'plain_text',
                    text: 'Message starred! :)',
                    emoji: true
                }
            },
            {
                type: 'image', // image block
                imageUrl: 'https://cdn0.iconfinder.com/data/icons/new-year-holidays-set/200/NewYearIcon7-01-1024.png',
                altText: 'test image'
            },
        ])

        //messageCreator.setText('Message starred! :)');
        messageCreator.setRoom(context.message.room);
        await modify.getCreator().finish(messageCreator);
    }
TypeScript

Now, instead of the image, we will add a divider and an action block. The action block contains a button element.

async executePostMessageStarred(context: IMessageStarContext, read: IRead, http: IHttp, persistence: IPersistence, modify: IModify): Promise<void> {
        const messageCreator = modify.getCreator().startMessage();
        const appId = this.getID();

        messageCreator.setBlocks([
            {
                type: 'section', // the section block
                blockId: 'section_1',
                text: {
                    type: 'plain_text',
                    text: 'Message starred! :)',
                    emoji: true
                }
            },
            {
                type: 'divider', // the divider block
                appId: appId,
                blockId: 'divider_block_1'
            },
            {
                type: 'actions', // the action block
                appId: appId,
                blockId: 'action_block_1',
                elements: [ // the elements parameter contains the action element details, in this case, a button element
                    {
                        type: 'button',
                        actionId: 'button_action_1',
                        appId: appId,
                        blockId: 'button_action_block_1',
                        text: {
                            type: 'plain_text',
                            text: 'Learn more!'
                        },
                        style: 'primary',
                        value: 'Button element'
                    }
                ]
            },
        ])

        //messageCreator.setText('Message starred! :)');
        messageCreator.setRoom(context.message.room);
        await modify.getCreator().finish(messageCreator);
    }
TypeScript

The following screenshot shows the UI:

We will define an input block containing the static menu element type:

async executePostMessageStarred(context: IMessageStarContext, read: IRead, http: IHttp, persistence: IPersistence, modify: IModify): Promise<void> {
        const messageCreator = modify.getCreator().startMessage();
        const appId = this.getID();

        messageCreator.setBlocks([
            {
                type: 'section', // the section block
                blockId: 'section_1',
                text: {
                    type: 'plain_text',
                    text: 'Message starred! :)',
                    emoji: true
                }
            },
            {
                type: 'divider', // the divider block
                appId: appId,
                blockId: 'divider_block_1'
            },
            {
                type: 'actions', // the action block
                appId: appId,
                blockId: 'action_block_1',
                elements: [ // the elements parameter contains the action element details, in this case, a button element
                    {
                        type: 'button',
                        actionId: 'button_action_1',
                        appId: appId,
                        blockId: 'button_action_block_1',
                        text: {
                            type: 'plain_text',
                            text: 'Learn more!'
                        },
                        style: 'primary',
                        value: 'Button element'
                    }
                ]
            },
            {
                type: 'input', // the input block
                appId: appId,
                blockId: 'input_block',
                label: {
                    type: 'plain_text',
                    text: 'static_input'
                },
                element: { // the "element" object contains the definition of the type of input block you want to use, in this case, a static select menu
                    type: 'static_select',
                    actionId: 'static_select_action_1',
                    appId: appId,
                    blockId: 'static_select_block_1',
                    placeholder: {
                        type: 'plain_text',
                        text: 'Select an option:',
                    },
                    options: [
                        {
                            value: 'option_1',
                            text: {
                                type: 'plain_text',
                                text: 'This is your first option'
                            }
                        },
                        {
                            value: 'option_2',
                            text: {
                                type: 'plain_text',
                                text: 'This is your second option'
                            }
                        }
                    ]
                }
            }
        ])

        //messageCreator.setText('Message starred! :)');
        messageCreator.setRoom(context.message.room);
        await modify.getCreator().finish(messageCreator);
    }
TypeScript

The following screenshot shows the blocks returned by the app bot:

To the previous code snippet, we will add a context block definition as follows:

{
                type: 'context', // the context block
                appId: appId,
                blockId: 'context_block',
                elements: [
                  {
                    type: 'plain_text',
                    text: 'This is a context block'
                  }
                ]
              },
        ])

        //messageCreator.setText('Message starred! :)');
        messageCreator.setRoom(context.message.room);
        await modify.getCreator().finish(messageCreator);
    }
TypeScript

The following screenshot shows what the context block looks like:

To this example, we will now add a preview block as follows:

{
                type: 'preview', // the preview block
                description: [
                  {
                    type: 'plain_text',
                    text: 'Description of preview'
                  }
                ],
                title: [
                  {
                    type: 'plain_text',
                    text: 'Title of preview'
                  }
                ]
              },        
        
        ])

        //messageCreator.setText('Message starred! :)');
        messageCreator.setRoom(context.message.room);
        await modify.getCreator().finish(messageCreator);
    }
TypeScript

The following screenshot shows how the preview block appears in the UI: