Sometimes your app needs to run within an iframe. For example, Intercom's chat widget which needs to be style-sandboxed from the rest of the page is run in an iFrame. My app wraps a navigation component inside an iFrame for better performance in the rest of the page.
The only thing that can't be worked around in this situation is Svelte's CSS transitions. They add the animation styles to the global (top-level) document and not the component's document.
For Svelte's transitions to work, Svelte will need to support adding styles to the document a component lives in.
I've created a solution which works well and avoids memory leaks. I reference this ticket in the PR.
@jacwright , do you have a simple REPL to demo how to render content in an iFrame ? I wanted to do this but I couldn't figure it out :)
Unfortunately because the REPL sandboxes it's iframe, any iframes within it are sandboxed and it doesn't work. In the test I added as part of the pull request I include a Frame.svelte component which you can use. You'll need to add the styles to the body in the onload event, but it should work.
I did try to get it working with the REPL.
ok, I'll look , thanks...
Just in case you were unaware; www.codesandbox.io also has a Svelte template, and you can "pop out" the preview pane in to a separate (non-framed) window, maybe that'll help your PR 🙂
Unless I can load a branch of Svelte into www.codesandbox.io I don't know if that will help determine the PR correctly fixes any issues.
I'm also in a similar situation.
From what I saw the compiler returns the javascript and css code for every .svelte component, then the bundler just bundles the code in 2 separate files: bundle.js and bundle.css
I think we need something similar to <svelte:head> but for iframes.
Maybe <svelte:iframe target={myiFrame}>css code
@jacwright I'm also interested on how to add content to an iFrame. I managed to do this by manually creating a component, but I don't think this is the best solution.
Here is code, let me know if your solution is better. My problem is the name is not updated in the FrameBody component and I need to usecomponent.$set(props) se update properties, which is against svelte framework.
<script>
import FrameBody from './FrameBody.svelte';
let name = "Jim";
function frameLoaded(ev) {
const iframe = ev.target;
const component = new FrameBody({
target: iframe.contentWindow.document.body,
props: {
name: name
}
});
}
function changeName() {
name = 'Tim';
}
</script>
<h2>{name}</h2>
<iframe on:load="{frameLoaded}"></iframe>
<div>
<button on:click={changeName}>Change name</button>
</div>
I also need this feature implemented.
@jacwright is there a way to use your pull requests inside my project?
@2beers I use a Svelte component to simplify the iframe. See https://gist.github.com/jacwright/7003916d7ae402b528dbaaca3061ca92#file-app-svelte-L6 as an untested example.
@Tzelon you could clone my branch locally, then:
npm run build
npm link
cd ../path/to/your/project
npm link svelte
That's how I'm using it right now.
Oh yeah, that gist is from the REPL. It just didn't work in the REPL because of sandboxing issues. https://svelte.dev/repl/7003916d7ae402b528dbaaca3061ca92?version=3.12.1
@Tzelon you could clone my branch locally, then:
- build svelte
- link svelte (for local use)
- link inside your project
npm run build npm link cd ../path/to/your/project npm link svelteThat's how I'm using it right now.
Works perfectly
Is this specific to transitions and animations, or is this an issue for all styles? I'm trying to render a component with an iframe document body as the target, and all component styles get appended to the root document head.
It looks like Svelte briefly had support for styles in an iframe by accessing ownerDocument (added in #362), but was removed later (in #377).
@jtormey This PR is specific to transitions and animations. It would be great to get another PR for component styles.
Thanks! I'll take a look at that. In the meantime, were you able to find a workaround that allowed you to inject component styles generated by Svelte into the iframe for your navigation component?
My iframe component does this little number on load:
Array.from(document.querySelectorAll('style, link[rel="stylesheet"]')).forEach(node => head.appendChild(node.cloneNode(true)));
Here it is in context:
import { onMount, onDestroy } from 'svelte';
export let component;
let frame; // bound in HTML with <iframe bind:this={frame}>
let content;
function onLoad() {
const head = frame.contentDocument.head;
const body = frame.contentDocument.body;
Array.from(document.querySelectorAll('style, link[rel="stylesheet"]'))
.forEach(node => head.appendChild(node.cloneNode(true)));
if (component) {
const { component, ...props } = $$props;
content = new component({
target: body,
props,
});
}
}
onMount(async () => {
if (frame.contentDocument.readyState === 'complete' && frame.contentDocument.defaultView) {
onLoad();
} else {
frame.addEventListener('load', onLoad);
}
});
onDestroy(() => {
if (frame) frame.removeEventListener('load', onLoad);
if (content) content.$destroy();
});
This is great! Thanks for sharing.
I can see that the PR for this issue is still opened. Are there any updates on this? (my app really needs this feature). Thanks in advance.
I haven't had the time to update the PR to the latest version of Svelte and resubmit. I should be able to soon (in the next month). Sorry for the delay!
It helps knowing others need this too.
This has been released in 3.20.0, thank you!
@jacwright
Is there a way to take only the app styles instead of taking all the styles of the parent?
I’m not sure. I know you can export your app’s css separately in the build
step, so maybe do that and put a data-attribute on the link element loading
the style sheet or something like that.
On Tue, Apr 21, 2020 at 3:16 PM naorye notifications@github.com wrote:
@jacwright https://github.com/jacwright Is there away to take only the
app styles instead of taking all the styles of the parent?—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
https://github.com/sveltejs/svelte/issues/3624#issuecomment-617418440,
or unsubscribe
https://github.com/notifications/unsubscribe-auth/AAA5LZV7OMA5S4ZQM2V7LDTRNYEKZANCNFSM4I26L7RQ
.
@jacwright You right. Thats what I've done.
Eventually I managed to add an actual iframe (not rendered by svelte) which isolated the styles completely. Thanks!