-
Notifications
You must be signed in to change notification settings - Fork 323
feat: auto resize with the autoResizeIframe prop #56
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -12,6 +12,8 @@ export interface HTMLResourceRendererProps { | |
| onUIAction?: (result: UIActionResult) => Promise<any>; | ||
| style?: React.CSSProperties; | ||
| proxy?: string; | ||
| iframeRenderData?: Record<string, unknown>; | ||
| autoResizeIframe?: boolean | { width?: boolean; height?: boolean }; | ||
| iframeProps?: Omit<React.HTMLAttributes<HTMLIFrameElement>, 'src' | 'srcDoc' | 'ref' | 'style'>; | ||
| } | ||
| ``` | ||
|
|
@@ -38,6 +40,7 @@ The component accepts the following props: | |
| - **`style`**: (Optional) Custom styles for the iframe. | ||
| - **`proxy`**: (Optional) A URL to a proxy script. This is useful for hosts with a strict Content Security Policy (CSP). When provided, external URLs will be rendered in a nested iframe hosted at this URL. For example, if `proxy` is `https://my-proxy.com/`, the final URL will be `https://my-proxy.com/?url=<encoded_original_url>`. For your convenience, mcp-ui hosts a proxy script at `https://proxy.mcpui.dev`, which you can use as a the prop value without any setup (see `examples/external-url-demo`). | ||
| - **`iframeProps`**: (Optional) Custom props for the iframe. | ||
| - **`autoResizeIframe`**: (Optional) When enabled, the iframe will automatically resize based on messages from the iframe's content. This prop can be a boolean (to enable both width and height resizing) or an object (`{width?: boolean, height?: boolean}`) to control dimensions independently. | ||
|
|
||
| ## How It Works | ||
|
|
||
|
|
@@ -67,6 +70,38 @@ By default, the iframe stretches to 100% width and is at least 200px tall. You c | |
|
|
||
| See [Client SDK Usage & Examples](./usage-examples.md) for examples using the recommended `<UIResourceRenderer />` component. | ||
|
|
||
| ## Auto-Resizing the Iframe | ||
|
|
||
| To make the iframe auto-resize, two things need to happen: | ||
| 1. The `autoResizeIframe` prop must be set in `htmlProps`when rendering `<UIResourceRenderer />`). | ||
| 2. The content inside the iframe must send a `ui-size-change` message to the parent window when its size changes. | ||
|
|
||
| The payload of the message should be an object with `width` and/or `height` properties. | ||
|
|
||
| ### Example Iframe Implementation | ||
|
|
||
| Here is an example of how you can use a `ResizeObserver` within your iframe's content to notify the host application of size changes: | ||
|
|
||
| ```javascript | ||
| const resizeObserver = new ResizeObserver((entries) => { | ||
| entries.forEach((entry) => { | ||
| window.parent.postMessage( | ||
| { | ||
| type: "ui-size-change", | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Perhaps
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. note that all the other events start with export const InternalMessageType = {
UI_ACTION_RECEIVED: 'ui-action-received',
UI_ACTION_RESPONSE: 'ui-action-response',
UI_ACTION_ERROR: 'ui-action-error',
UI_SIZE_CHANGE: 'ui-size-change',
UI_LIFECYCLE_IFRAME_READY: 'ui-lifecycle-iframe-ready',
UI_LIFECYCLE_IFRAME_RENDER_DATA: 'ui-lifecycle-iframe-render-data',
}; |
||
| payload: { | ||
| height: entry.contentRect.height, | ||
| }, | ||
| }, | ||
| "*", | ||
| ); | ||
| }); | ||
| }); | ||
|
|
||
| resizeObserver.observe(document.documentElement) | ||
| ``` | ||
|
|
||
| This will observe the root `<html>` element and send a message whenever its height changes. The `<HTMLResourceRenderer />` will catch this message and adjust the iframe's height accordingly. You can also include `width` in the payload if you need to resize the width. | ||
|
|
||
| ## Security Notes | ||
|
|
||
| - **`sandbox` attribute**: Restricts what the iframe can do. `allow-scripts` is required for JS execution. In the external URL content type, `allow-same-origin` is needed for external apps. Other than these inclusions, all other capabilities are restricted (e.g., no parent access, top-level navigations, modals, forms, etc.) | ||
|
|
||
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
|
|
@@ -140,6 +140,8 @@ export const InternalMessageType = { | |||||
| UI_ACTION_RESPONSE: 'ui-action-response', | ||||||
| UI_ACTION_ERROR: 'ui-action-error', | ||||||
|
|
||||||
| UI_SIZE_CHANGE: 'ui-size-change', | ||||||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
|
|
||||||
| UI_LIFECYCLE_IFRAME_READY: 'ui-lifecycle-iframe-ready', | ||||||
| UI_LIFECYCLE_IFRAME_RENDER_DATA: 'ui-lifecycle-iframe-render-data', | ||||||
| }; | ||||||
|
|
||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Namespacing