RHS Popout Support for Plugins

What’s changing?

Beginning in Mattermost v11.3 (January 2026 release), some plugins that register a Right Hand Sidebar (RHS) component using registerRightHandSidebarComponent will need to implement additional code to support RHS popouts if their RHS component relies on plugin-specific state.

Why are we making this change?

RHS popouts allow users to open the right-hand sidebar in a separate window. When a popout window is created, it starts with a fresh Redux store that doesn’t contain the plugin’s state from the parent window. If your plugin’s RHS component depends on state that isn’t automatically synchronized, it won’t function correctly in the popout window without explicit state synchronization.

Who may be affected?

If you maintain a plugin that:

  • Uses registerRightHandSidebarComponent to register an RHS component, and
  • Your RHS component relies on plugin-specific state stored in Redux

Then you will need to update your plugin to support RHS popouts. If your RHS component is self-contained and doesn’t rely on any plugin-specific state, no changes are required.

What do you need to do as a plugin maintainer?

If your plugin’s RHS component relies on plugin-specific state, you need to:

  1. Register a listener to handle state requests from popout windows
  2. Load any necessary content when initializing in a popout window

An example of the required changes is below (from this PR):

import {getSidebarContent, updateRhsState} from '@/actions';

class PluginClass {
    async initialize(registry, store) {
        // ... other registrations ...
        
        const {showRHSPlugin} = registry.registerRightHandSidebarComponent(SidebarRight, 'MyPlugin');
        store.dispatch(setShowRHSAction(() => store.dispatch(showRHSPlugin)));

        // Register listener to handle state requests from popout windows
        if (registry.registerRHSPluginPopoutListener) {
            registry.registerRHSPluginPopoutListener(pluginId, (teamName, channelName, listeners) => {
                listeners.onMessageFromPopout((channel) => {
                    if (channel === 'GET_RHS_STATE') {
                        // Send your plugin's RHS state to the popout window
                        listeners.sendToPopout('SEND_RHS_STATE', store.getState()[`plugins-${manifest.id}`].rhsState);
                    }
                });
            });
            // Handle popout window initialization
            if (window.WebappUtils.popouts && window.WebappUtils.popouts.isPopoutWindow()) {
                // Load any necessary content for the RHS
                store.dispatch(getSidebarContent());
                
                // Listen for state updates from the parent window
                window.WebappUtils.popouts.onMessageFromParent((channel, state) => {
                    if (channel === 'SEND_RHS_STATE') {
                        // Update your plugin's state with the state from the parent window
                        store.dispatch(updateRhsState(state));
                    }
                });
                
                // Request the current RHS state from the parent window
                window.WebappUtils.popouts.sendToParent('GET_RHS_STATE');
            }
        }
        
        // ... rest of initialization ...
    }
}

Key points:

  • registerRHSPluginPopoutListener allows your plugin to respond to state requests from popout windows, providing listeners to do so
  • window.WebappUtils.popouts.isPopoutWindow() detects if the current window is a popout
  • window.WebappUtils.popouts.sendToParent() sends messages to the parent window
  • window.WebappUtils.popouts.onMessageFromParent() receives messages from the parent window

Note: The channel names ('GET_RHS_STATE' and 'SEND_RHS_STATE') and the structure of the state you pass are up to you - you can customize them based on your plugin’s needs. The example above uses a simple pattern that works for most cases.

The registerRHSPluginPopoutListener API and popout utilities are available in Mattermost v11 and later, and plugins that don’t implement this will continue to work in non-popout contexts. For backwards compatibility with older Mattermost versions, you should check that registry.registerRHSPluginPopoutListener exists before calling it, and check that window.WebappUtils.popouts exists before using popout-related methods.