-
Notifications
You must be signed in to change notification settings - Fork 77
Resizing iframe heights for storybook examples #3789
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
73b8b33
024893c
445acfd
b6bed8c
412c5a7
14a9701
5ec1537
01bfef1
820e775
b0283e3
d9d81d2
9f11939
bc697f4
949cda6
a2ba690
059a1d4
3a019a0
829c278
253b9aa
3185e84
10d1f6f
dd86ef2
1113b25
1f43cda
9e6464a
dd7e204
6354264
41ecd4d
0b68412
c2de8b5
f435a8e
2de21c6
2788927
9932169
b322a1f
88afb82
23ce14a
9dc845c
52cd9b6
176024b
f9cc21c
a123ec3
c221552
2cb4d44
05b1c73
cc9e497
fe0a1a9
18cdc5b
081ac91
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 | ||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
@@ -1,6 +1,18 @@ | ||||||||||||||||||
{% assign storybook_path = site.storybook_path %} | ||||||||||||||||||
{% if include.is_mobile %}{% assign storybook_path = site.storybook_mobile_path %}{% endif %} | ||||||||||||||||||
{% assign storybook_iframe_path = storybook_path | append: '/iframe.html?id=' | append: include.story | append: '&viewMode=story' %} | ||||||||||||||||||
{% if include.is_mobile %} | ||||||||||||||||||
{% assign storybook_path = site.storybook_mobile_path %} | ||||||||||||||||||
{% endif %} | ||||||||||||||||||
{% assign storybook_iframe_path = storybook_path | append: '/iframe.html?id=' | append: include.story | append: '&viewMode=story' %} | ||||||||||||||||||
|
||||||||||||||||||
<style> | ||||||||||||||||||
iframe { | ||||||||||||||||||
border: none; | ||||||||||||||||||
width: 100%; | ||||||||||||||||||
opacity: 0; | ||||||||||||||||||
transition: opacity 0.3s ease; | ||||||||||||||||||
display: block; | ||||||||||||||||||
} | ||||||||||||||||||
</style> | ||||||||||||||||||
|
||||||||||||||||||
{% if include.scrollable %} | ||||||||||||||||||
<div | ||||||||||||||||||
|
@@ -20,15 +32,59 @@ | |||||||||||||||||
style="max-width: {{ include.width | default: '100%' }}" | ||||||||||||||||||
> | ||||||||||||||||||
<iframe | ||||||||||||||||||
width="100%" | ||||||||||||||||||
height="{{ include.height }}" | ||||||||||||||||||
class="storybook-embed" | ||||||||||||||||||
id="{{ include.story }}" | ||||||||||||||||||
src="{{ storybook_iframe_path }}" | ||||||||||||||||||
title="Storybook: {{ include.story }}" | ||||||||||||||||||
{% if include.auto_resize == false %} | ||||||||||||||||||
data-auto-resize="false" | ||||||||||||||||||
style="width: 100%; height: {{ include.height | default: '150px' }}; border: none;" | ||||||||||||||||||
{% else %} | ||||||||||||||||||
data-auto-resize="true" | ||||||||||||||||||
style="width: 100%; border: none;" | ||||||||||||||||||
{% endif %} | ||||||||||||||||||
></iframe> | ||||||||||||||||||
</div> | ||||||||||||||||||
{% endif %} | ||||||||||||||||||
|
||||||||||||||||||
{% assign story_name_prefix = '' %} | ||||||||||||||||||
{% if include.is_mobile %}{% assign story_name_prefix = 'va-mobile_' %}{% endif %} | ||||||||||||||||||
{% if include.is_mobile %} | ||||||||||||||||||
{% assign story_name_prefix = 'va-mobile_' %} | ||||||||||||||||||
{% endif %} | ||||||||||||||||||
{% assign storybook_preview_path = site.storybook_path | append: '/?path=/story/' | append: story_name_prefix | append: include.story %} | ||||||||||||||||||
|
||||||||||||||||||
[{% if include.link_text %}<img aria-hidden="true" role="img" src="{{ site.baseurl }}/images/storybook.svg" class="site-component-resources-links__icon" width="16px" alt="Storybook logo">View {{ include.link_text}}{% else %}See this{% endif %} in Storybook]({{ storybook_preview_path }}) | ||||||||||||||||||
[<img aria-hidden="true" role="img" src="{{ site.baseurl }}/images/storybook.svg" class="site-component-resources-links__icon" width="16px" alt="Storybook logo">View {{ include.link_text | default: 'this' }} in Storybook]({{ storybook_preview_path }}) | ||||||||||||||||||
|
||||||||||||||||||
<script> | ||||||||||||||||||
function resizeIframes() { | ||||||||||||||||||
const iframes = document.querySelectorAll('iframe.storybook-embed'); | ||||||||||||||||||
|
||||||||||||||||||
iframes.forEach((iframe) => { | ||||||||||||||||||
// Skip if data-auto-resize is explicitly false | ||||||||||||||||||
if (iframe.dataset.autoResize === 'false') return; | ||||||||||||||||||
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. In what situations would we not want it to resize? Are there many stories that we have to manually set the 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. Barb gave the example of Back to Top. I suspect there are a few more. 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. I also used this feature to turn off the resize for the modals so we could manually apply the heights. I was thinking of manually applying the height to some of the components that still have a scroll bar, like the progress bar and expandable alert, so we can get to a state where there is no scrolling in the iframes. |
||||||||||||||||||
|
||||||||||||||||||
try { | ||||||||||||||||||
const iframeDoc = iframe.contentDocument || iframe.contentWindow.document; | ||||||||||||||||||
if (!iframeDoc) return; | ||||||||||||||||||
|
||||||||||||||||||
const newHeight = iframeDoc.body.scrollHeight; | ||||||||||||||||||
|
||||||||||||||||||
if (iframe.dataset.lastHeight != newHeight) { | ||||||||||||||||||
iframe.style.height = newHeight + 35 + 'px'; | ||||||||||||||||||
iframe.dataset.lastHeight = newHeight; | ||||||||||||||||||
} | ||||||||||||||||||
} catch (err) { | ||||||||||||||||||
console.warn('Cannot access iframe content due to cross-origin restrictions:', err); | ||||||||||||||||||
} | ||||||||||||||||||
}); | ||||||||||||||||||
} | ||||||||||||||||||
|
||||||||||||||||||
setInterval(resizeIframes, 500); | ||||||||||||||||||
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. There might be some concern with using Is it possible to just use 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. I think this is what allows it to be responsive to the user interacting with the components in the iFrames, which I quite like. But I see the performance concerns. We could either give up on that or find another way to trigger the resize. But that seems difficult given that the components are in iFrames. Thoughts? 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. It would be ideal to fix the performance issues. I asked ChatGPT about this just now. Two prompts about improving performance and then also keeping the feature of dynamically resizing iframes. Great follow-up — the answer depends on which method you choose and whether your iframes are same-origin or cross-origin. Here's a breakdown of the options and their behavior when components inside the iframe (like modals, accordions, tabs, etc.) cause the height to change dynamically: ✅ 1. Using postMessage + ResizeObserver (inside Storybook)☑️ Best for cross-origin setups This works even when content expands later (e.g., a modal opens, an accordion expands), because ResizeObserver tracks content size changes in the iframe and posts new height to the parent. 🛠️ Requires adding this JavaScript to the Storybook's preview-body.html:
And the parent page just listens:
✅ Result: Resizes whenever content changes — no constant polling on parent.
|
Approach | Cross-Origin | Dynamic Content | Performance |
---|---|---|---|
postMessage + ResizeObserver | ✅ | ✅ | ✅ |
Parent-side setInterval | ❌ (X-origin) | ❌ | |
Manual height via include | ✅ | ❌ | ✅ |
—
💡 Recommendation:
Use the ResizeObserver + postMessage approach for dynamic resizing with minimal performance overhead — especially when your Storybook iframe is hosted separately (Netlify, GitHub Pages, etc.).
Would you like me to give you a drop-in version for your setup that only touches the parent and the preview-body.html inside Storybook?
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.
dynamically resizing iframes
In that case, using ResizeObserver
would be preferred if it's possible. This is the approach we use for a few component-library components as well.
But it will require updating the Storybook package too in order to send a message
. I think that's how Andres was originally going to try and approach the problem:
We might be able to dispatch an event in Storybook and update the height when we know this element exists in the DOM as a workaround.
Your AI suggestion for the ResizeObserver
approach still wants to use setInterval as a fallback anyway.
// Fallback: post periodically in case ResizeObserver misses changes
setInterval(postHeight, 500);
I guess for the sake of time, we can go with the single setInterval
approach but I suspect that, if there are issues loading Storybook (like for local development), we might see some odd behavior.
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.
Given that it would be a fallback we could also push that setInterval time out a bit (1000? 1500?)
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.
It does not seem to work for the mobile stories:
https://dev-design.va.gov/3789/components/alert/#mobile
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.
Barb accounted for this under known issues:
There are only 7 mobile components thus far. I'm willing to let this go until we figure out where the mobile components are going to ultimately live.