# useIncomingPostMessages

*Category:* Utilities
*Section:* Browser & device hooks
*Source:* https://uikit.developers.rio.cloud/#/utilities/useIncomingPostMessages
*Captured:* 2026-04-27T14:59:39.988Z

For handling postMessage events in React components.

## useIncomingPostMessages

You can either handle "vanilla" events yourself or declaratively listen to "action-style" events. The latter are inspired by Redux actions, as the event data is an object with a type property and an optional payload.

The payload does not have to be a simple string, but can be a complex object, as well.

### Example: Example 1

Send raw message ("hello, world") Send action: EVENT_WIDGET_READY Send action: EVENT_WIDGET_DATA
Note that in this simple example, we're not really sending messages across windows. The origin-filtering handlers are in place, though. You can experiment by opening this page in an iframe inside a page with a different origin and try sending the same events as in the example code.
Simple events
Shows every incoming postMessage as-is (no origin filter or type parsing). Useful for quick debugging of any messages your page receives.

Simple events with origin filter
Same raw view, but driven by the origin+handler object form (instead of a single callback) and only for messages whose origin matches this page.

Action events
Only shows action-style messages (objects with a `type` field) and extracts their payload. Handy when you control the sender and use message types to route logic.

Action events with origin filter
Action messages constrained by origin. Use this to route typed messages while still protecting against unexpected origins.

#### React (tsx)

```tsx
import { useEffect, useRef, useState } from 'react';

import ButtonToolbar from '@rio-cloud/rio-uikit/ButtonToolbar';
import Button from '@rio-cloud/rio-uikit/components/button/Button';
import useIncomingPostMessages from '@rio-cloud/rio-uikit/hooks/useIncomingPostMessages';

export default () => {
    const [simpleEvents, setSimpleEvents] = useState<string[]>([]);
    const [filteredSimpleEvents, setFilteredSimpleEvents] = useState<string[]>([]);
    const [actionEvents, setActionEvents] = useState<string[]>([]);
    const [filteredActionEvents, setFilteredActionEvents] = useState<string[]>([]);

    useIncomingPostMessages(event => {
        // We're getting ALL kinds of events here, so we need to implement appropriate filters ourselves!
        if (isReactDevtoolsEvent(event)) {
            return;
        }

        setSimpleEvents([...simpleEvents, JSON.stringify(event.data)]);
    });

    useIncomingPostMessages({
        // this will ignore all events not coming from a declared origin - in this simple example, we're just using the current page's origin itself
        origin: window.origin,
        handler: event => {
            // We're getting ALL kinds of events here, so we need to implement appropriate filters ourselves!
            if (isReactDevtoolsEvent(event)) {
                return;
            }

            setFilteredSimpleEvents([...filteredSimpleEvents, JSON.stringify(event.data)]);
        },
    });

    useIncomingPostMessages({
        handlers: {
            EVENT_WIDGET_READY: (payload: string) => {
                setActionEvents([...actionEvents, payload]);
            },
            EVENT_WIDGET_DATA: (payload: unknown) => {
                const message = typeof payload === 'string' ? payload : JSON.stringify(payload);
                setActionEvents([...actionEvents, message]);
            },
        },
    });

    useIncomingPostMessages({
        // this will ignore all events not coming from a declared origin - in this simple example, we're just using the current page's origin itself
        origin: window.origin,
        handlers: {
            EVENT_WIDGET_READY: (payload: string) => {
                setFilteredActionEvents([...filteredActionEvents, payload]);
            },
            EVENT_WIDGET_DATA: (payload: unknown) => {
                const message = typeof payload === 'string' ? payload : JSON.stringify(payload);
                setFilteredActionEvents([...filteredActionEvents, message]);
            },
        },
    });

    const sendSimpleEvent = () => {
        window.postMessage('hello, world');
    };

    const sendActionEvent = (type: 'EVENT_WIDGET_READY' | 'EVENT_WIDGET_DATA') => {
        const payload =
            type === 'EVENT_WIDGET_READY'
                ? 'Widget is ready to receive data'
                : {
                      widgetId: 'demo-widget',
                      user: 'Jane Doe',
                      shipment: { orderId: 'ORD-1001', status: 'ready', etaDays: 2 },
                  };
        window.postMessage({ type, payload });
    };

    return (
        <>
            <ButtonToolbar>
                <Button onClick={() => sendSimpleEvent()}>Send raw message ("hello, world")</Button>
                <Button onClick={() => sendActionEvent('EVENT_WIDGET_READY')}>Send action: EVENT_WIDGET_READY</Button>
                <Button onClick={() => sendActionEvent('EVENT_WIDGET_DATA')}>Send action: EVENT_WIDGET_DATA</Button>
            </ButtonToolbar>

            <p>
                Note that in this simple example, we're not really sending messages across windows. The origin-filtering
                handlers are in place, though. You can experiment by opening this page in an iframe inside a page with a
                different origin and try sending the same events as in the example code.
            </p>

            <div className='display-grid grid-cols-1 grid-cols-2-md margin-y-20 gap-25'>
                <div>
                    <h5>Simple events</h5>
                    <p className='text-color-darker margin-y-10'>
                        Shows every incoming postMessage as-is (no origin filter or type parsing). Useful for quick
                        debugging of any messages your page receives.
                    </p>
                    <EventTextarea events={simpleEvents} />
                </div>
                <div>
                    <h5>Simple events with origin filter</h5>
                    <p className='text-color-darker margin-y-10'>
                        Same raw view, but driven by the origin+handler object form (instead of a single callback) and
                        only for messages whose origin matches this page.
                    </p>
                    <EventTextarea events={filteredSimpleEvents} />
                </div>
                <div>
                    <h5>Action events</h5>
                    <p className='text-color-darker margin-y-10'>
                        Only shows action-style messages (objects with a `type` field) and extracts their payload. Handy
                        when you control the sender and use message types to route logic.
                    </p>
                    <EventTextarea events={actionEvents} />
                </div>
                <div>
                    <h5>Action events with origin filter</h5>
                    <p className='text-color-darker margin-y-10'>
                        Action messages constrained by origin. Use this to route typed messages while still protecting
                        against unexpected origins.
                    </p>
                    <EventTextarea events={filteredActionEvents} />
                </div>
            </div>
        </>
    );
};

const EventTextarea = ({ events }: { events: string[] }) => {
    const textareaRef = useRef<HTMLTextAreaElement>(null);

    useEffect(() => {
        const element = textareaRef.current;
        if (element) {
            element.scrollTop = element.scrollHeight;
        }
    }, [events]);

    return (
        <div>
            <textarea
                ref={textareaRef}
                readOnly
                spellCheck={false}
                value={events.join('\n')}
                className='form-control width-100pct min-height-150 padding-15'
            />
        </div>
    );
};

const isReactDevtoolsEvent = (event: MessageEvent<unknown>) => {
    if (typeof event.data === 'object' && event.data !== null) {
        const source = (event.data as Record<string, unknown>).source;
        return typeof source === 'string' && source.startsWith('react-devtools-');
    }
    return false;
};
```

#### Props: Simple event handler

### Simple event handler

| Name | Type | Default | Description |
| --- | --- | --- | --- |
| handler | (event: MessageEvent<unknown>) => void | — | A callback function triggered when a message is received. |

#### Props: Simple handler with origin filtering

### Simple handler with origin filtering

| Name | Type | Default | Description |
| --- | --- | --- | --- |
| options | object | — | An object holding the handler and the expected event origin. |
| └origin | string | — | The origin for which events are accepted. All other events are ignored. |
| └handler | (event: MessageEvent<unknown>) => void | — | A callback function triggered when a message is received. |

#### Props: Declarative, action-style handlers

### Declarative, action-style handlers

| Name | Type | Default | Description |
| --- | --- | --- | --- |
| options | object | — | An object holding the handlers and the expected event origin. |
| └origin | string | "*" | The origin for which events are accepted. All other events are ignored. Optional; defaults to "*". |
| └handlers | Record<string, (payload: unknown) => void> | — | Map of callbacks to be registered. Object keys describe the event action "type". The handler will be called with the payload. |