Injecting styles into an iframe using Javascript in a vue.js environment

When working within the admin area of a website builder, I aim to provide users with a visual preview of style changes before they save any updates.

To achieve this, I use an iframe to display the user's website, allowing for visual adjustments to be made directly. Although the admin site and the user's site may have different codebases and custom domain names, which could potentially present some issues.

I have implemented a Content-Security-Policy to enable the admin area to fetch the iframe, and this is functioning as expected. However, I am facing difficulties in appending a temporary <style> tag to the head.

Here is a snippet of the code:

<template>
    <div class="designer">
        <div class="designer-sidebar">
        <!-- style options -->
        </div>

        <div class="designer-content">
            <iframe id="the-iframe" class="designer-frame" src="http://thechildsite.com" frameborder="0" width="100%" height="100%">
                <p>Your browser does not support iframes.</p>
            </iframe>
        </div>
    </div>
</template>

<script>
    export default {
        data () {
            return {
                updating: false,
                device: 'desktop'
            }
        },
        ready () {
            var iframe = document.getElementById('the-iframe')
            var style = document.createElement('style')
            style.textContent =
                'body {' +
                '  background-color: lime;' +
                '  color: pink;' +
                '}'
            ;
            iframe.contentDocument.head.appendChild(style)
        }
    }
</script>

Answer №1

After testing your code, I noticed that the var iframe always returns null for me.

When I changed the ready() to mounted(), the var iframe was finally populated with the iframe.

Even the style tag wasn't being populated, so I attempted a different approach:

var css = document.createElement('style');
css.type = 'text/css';

var styles = 'body {' +
    '  background-color: lime;' +
    '  color: pink;' +
'}';

css.appendChild(document.createTextNode(styles));

iframe.contentDocument.head.appendChild(css);

Despite this, the style still doesn't get appended to the iframe (possibly due to permission issues on my end). However, when I console log the css, it seems like it's on the right track. Hopefully, this information provides some assistance!

Answer №2

With the assistance of a colleague, I was able to discover a solution involving the use of postMessage. For more information, visit:

Here is how it was implemented in the Vue.js application:

<div class="designer-content">
    <iframe ref="iframeContent" class="designer-frame" :src="liveSite" frameborder="0" width="100%" height="100%" @load="iframeStyles">
        <p>Your browser does not support iframes.</p>
    </iframe>
</div>

methods: {
    iframeStyles() {
        this.frame = this.$refs.iframeContent.contentWindow;

        const style =
            '.layout__wrapper {background:' + this.background + ';} ' +
            'body {color:' + this.text + ';} '
        this.frame.postMessage(style, '*');
    }
}

For the site to be iframed in:

window.addEventListener('message', function(e) {
    if (e.origin === 'https://app.theparentapp.com') {
        var style = document.createElement('style');
        style.textContent = e.data;
        document.head.appendChild(style);
    }
});

Hopefully, this solution will be beneficial to others as well.

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

What is the mechanism by which a custom hook, functioning as a trigger, initiates the re-rendering of a separate function component?

According to the official documentation on Custom React Hooks, one particular use case for utilizing a custom hook is demonstrated through the following example: function FriendListItem(props) { const isOnline = useFriendStatus(props.friend.id); retur ...

What could be causing the Material UI tabs to malfunction when dynamically populating the content using a .map function instead of manually inserting it?

I was able to successfully integrate Material UI's tabs by manually adding content, but when I attempted to use a .map function to populate the content from a JSON data source, it stopped working. Can someone help me figure out why? The only change I ...

Fade background position rollover effect

I'm facing a challenge with animating my background image using background positioning. The CSS is functioning correctly, but when I attempted to enhance it by adding jQuery for a rollover effect, the animation isn't working as expected. Can anyo ...

Why isn't the PHP snack bar working when clicking on an href <a> using onClick?

How can I dismiss this snackbar when the add to cart <a href> is clicked? I've tried but nothing seems to work. Can anyone provide some assistance? Here is my code: SNACKBAR CODE <div id="snackbar">Some text some message..</div> A ...

The advice I received was to avoid using max-width and instead utilize min-width when styling with CSS

With @media screen and (max-width:700px) { Link to image 1 Whenever I use @media screen and (min-width: 700px) { it messes up. How can I adjust it for min-width without causing issues? Link to image 2 ...

Exploring Head-Linked/Off-center View in Three.js

I'm attempting to create a permanent head-coupled perspective without relying on the full headtrackr library. My head will remain stationary, but it will not be directly facing the screen. For those interested, I have a small demonstration available ...

How can I show hidden column names in the Sencha Touch 2 date picker component with CSS?

I am currently utilizing a date and time picker that has the ability to display ['month', 'day', 'year','hour','minute','ampm']. You can find the source code here. Although everything is function ...

Show the extracted data on the following web page once it has been cleaned

I am looking to connect a python file with an HTML page using Flask application. On the first page (upload.html), the user is required to select the job field and job title from two dropdown menus. Afterwards, the user needs to upload a file containing a l ...

Stunning CSS Image Showcase

When hovering over my image gallery, it works fine. However, I would like the first image in the gallery to automatically appear in the enlarged section instead of displaying as a blank box until hovered over. <!DOCTYPE html> <html lang="en"> ...

When working with jQuery, I encountered the error message "is not a function" because I mistakenly tried to use a function more than

While working on a pager, I encountered an issue with a function that is initially invoked when the document loads. However, when attempting to use it a second time, an error "is not a function" occurs. I am curious about the reason behind this phenomenon. ...

Rendering a Subarray using Map in ReactJS

I have an object containing data structured like this: [{"groupid":"15","items":[ {"id":"42","something":"blah blah blah"}, {"id":"38","something":"blah blah blah"}]}, {"groupid":"7","items": [{"id":"86","something":"blah blah blah"}, {"id":"49","somethin ...

Angular - when removing items from ngRepeat, the remaining elements do not transition smoothly; instead, they abruptly snap or jump into position

Currently using AngularJS v1.4.8 with ngAnimate injected into my controller. In the process of creating a dynamic list using ngRepeat, tied to an array. The addition and updating of items in the list function smoothly with animations working as intended. ...

Refresh the form fields using PHP_SELF after submission

How can I pass a calculated value to another form field using php_self to submit a form on the same page? The $title_insurance field is not getting populated, any suggestions on what might be causing this? <?php if(isset($_POST['submit'])) { ...

Achieving a similar functionality to Spring Security ACL in a Node.js AWS Lambda serverless environment

I am tackling a javascript challenge that has me stumped. Specifically, I am trying to figure out how to implement fine-grained authorization using an AWS serverless approach. In Spring security ACL, users can be banned from specific tasks at the instanc ...

Is there a way to switch the language on the date-picker tool?

My date-picker has a unique set up: <input type="text" ng-readonly="true" class="form-control" datepicker-popup="yyyy-MM-dd" ng-model="filter.FInicial" is-open="filter.controlFInicialAbierto" min-date="minDateIni" max-date="maxDat ...

Is there a way to search for multiple items using just one search term?

On my app, there is a search bar that currently only looks up data for one specific attribute. For example, if I type in "Hammer," it only searches for Tool names. Now, I need to expand the search functionality to accommodate different types of strings. F ...

How to Utilize Custom Component Tag Names in CSS with Vue.js 2?

<template> <header> <hamburger></hamburger> <app-title></app-title> <lives></lives> </header> </template> <script> export default { name: 'Titlebar& ...

What is the process for showcasing specific data using Vue.js?

{ "status": "ok", "source": "n", "sortBy": "top", "articles": [ { "author": "Bradford ", "title": "friends.", "url": "http: //", "urlToImage": "http://" }, { ...

Expand the background of columns to cover grid gutters

Imagine this... You're working on a layout with three columns, all within a fixed-sized container that is centered using margin:0 auto. The design requires the first column to have a background color that reaches the left edge of the browser window. ...

Ways to locate CSS file path within a web browser

Currently, I am focusing on the theme development aspect of Magento2. After compiling the .less file, I noticed that two css files are generated: styles-l.css styles-m.css Despite trying to inspect the element and view the applied CSS in the browser, i ...