Add CSS styles directly into the shadow-root instead of the head tag | Vue.js and Webpack

Currently, I'm developing a widget that can be embedded on websites using Vue.js along with vue-custom-element. Everything was going well until I encountered an issue.

The problem arises when trying to integrate a component (along with its CSS) from a package such as vue-number-input. Despite my attempts to keep the CSS encapsulated within the shadow root, it ends up being injected into the head of the webpage.

You can observe this behavior in this screenshot, where the CSS from the number input package is placed in the head instead of the shadow root.

I have made all necessary adjustments to ensure that the application functions properly within the shadow root.

To further investigate this issue, I have shared my vue.config.js, my main.js file (where I register the custom element), and my component (where I import the package's component).

If anyone has insights on how to resolve this issue or if it is even feasible, please share your expertise.

Answer №2

After conducting extensive research to find a method that would lazy-load our styles into the shadow-root, we came up empty-handed. Ultimately, we had to settle for a less than ideal solution, which meant loading all the styles on initial load.

Note: While this workaround works for QA and production environments, during development, the styles will still be loaded within the head of the page. It's important to ensure that no other styles conflict with this setup.

Our approach to achieving this was as follows:

// vue.config.js

const webpack = require('webpack');

module.exports = {
  configureWebpack: {
    // ...
    plugins: [
      new webpack.optimize.LimitChunkCountPlugin({
        maxChunks: 1,
     }),
   ],
 },
 chainWebpack: (config) => {
   config.optimization.delete('splitChunks');
 },
};
// main.js

import createStyleLink from '@/helpers/createStyleLink';

// ...

const options = {};

// Enabling shadow root for the production build
if (process.env.NODE_ENV === 'production') {
  options.shadow = true;
  options.beforeCreateVueInstance = (root) => {
    const rootNode = root.el.getRootNode();
    if (rootNode instanceof ShadowRoot) {
      root.shadowRoot = rootNode;
    } else {
      root.shadowRoot = document.head;
    }
    // After deployment, this code will create a style link and place it inside the shadow root. 
    // Ideally, a CDN should be used for this purpose.
    createStyleLink(rootNode, `${process.env.VUE_APP_URL}/css/app.css`);
    return root;
  };
}

// ...

Vue.customElement('widget', App, options);
// createStyleLink.js

export default function (node, url) {
  const link = document.createElement('link');
  link.href = url;
  link.type = 'text/css';
  link.rel = 'stylesheet';
  node.appendChild(link);
}

I hesitate to label this as a perfect solution, as it is more of a makeshift fix for the issue at hand.

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

Having difficulty adjusting the width of a div element

I've been struggling to adjust the width of the div assigned with the colors class, whether in percentage or pixels. var colors = ["RED", "GREEN", "BLUE", "YELLOW", "PURPLE"]; for (var h = 0; h <= 4; h++) { for (var i = 0; i <= colors.lengt ...

Is it possible to generate a basic HTML page using Express JS without utilizing Ejs or any other templating engine

I have a basic HTML file with a Bootstrap form, along with a simple API coded within. In my server.js file, I've specified that when I request /about, it should redirect me to the about.html page. However, instead of redirecting, I'm encountering ...

Highcharts JS encountered an error: x[(intermediate value)(intermediate value)(intermediate value)] is not a valid constructor

I'm in the process of creating a bar chart by fetching options from an ajax response. However, I encountered an error when passing the object to the highcharts constructor. Uncaught TypeError: x[(intermediate value)(intermediate value)(intermediate v ...

Trigger Object RuntimeError

Initially, I attempted to pass the object :id to the URL and it was successful. However, when I tried to pass the object to the list, I encountered a ReferenceError. index.ejs: <tr> <th class="text-center">AWB NO</th> <th c ...

Having trouble getting the Facebook like button to display on my website using an iframe in the markup

I gave it my all to try and get it to work, but unfortunately, I was unsuccessful. This is the approach I took. First, I followed the instructions provided on https://developers.facebook.com/docs/plugins/like-button. Next, I copied and pasted the iframe ...

Handling AJAX requests using jQuery

I'm currently in the process of learning how to utilize jQuery Ajax. Could you explain to me the significance of function(response), as well as what exactly is meant by response == 1 and response == 2? jQuery.post(ajaxurl, data, function(response) { ...

Ways to have a list component smoothly descend when a dropdown menu is activated

I have a situation where I have a list with two buttons, and each button triggers the same dropdown content in a sidebar component. The issue is that when I click on one button to open the dropdown, the second button does not move down to make space for it ...

What is the best way to establish a default translation setting in i18n for Nuxt.js?

In my nuxt.config.js file, I had set the default routing like this : However, when I access localhost, it redirects to: http://localhost:3000/en. Shouldn't it redirect to http://localhost:3000/ instead? What can be done to resolve this issue? ...

Issue with Bootstrap 5: Mobile Menu Failure to Expand

I’ve been struggling with this issue for days now. I’ve searched everywhere for a solution, but to no avail. That’s why I’m turning to the experts here for help :-) The problem I’m facing is that my mobile menu won’t open. Nothing happens when ...

Offering various language options on a website determined by the URL

I've been contemplating how to add multi-language support to my personal website, which I developed using ExpressJS and NodeJS with EJS as the template engine. Currently, the website is only available in English, but I want to add a German version as ...

Make a copy of an array and modify the original in a different way

Apologies for my poor English, I will do my best to be clear. :) I am working with a 3-dimensional array which is basically an array of 2-dimensional arrays. My task is to take one of these 2-dimensional arrays and rotate it 90° counterclockwise. Here is ...

Inquiries regarding node.js

While delving into research on node.js and Mongodb, I encountered a few areas that require clarification. My aim is to query Mongodb from the web using JavaScript because of my familiarity with the language. Additionally, it aligns well with Mongodb' ...

Applying Media Queries Based on Element Height

Situation: In my scenario, there is an image with two buttons below it, all of which share the same width. Issue: When the viewport is too wide horizontally, the buttons are not visible without scrolling down. This poses a challenge for tablets and small ...

Handling typeError in Vue.js JavaScript filter for object manipulation

I need to sort an object based on state names (e.g. Berlin, Bayern ...). Below is the API response I received. "states":{ "Bayern":{ "total":13124737, "rs":"09", "va ...

I managed to pass an array of data to the client using EJS, but I encountered an issue trying to access the array on the client side after adding an index value

When I pass data received from an API to the client using EJS, I am struggling to access the JSON array on the client side. On the server side, I successfully send the returned data to the client like this: fetch(url) .then(res => res.json()) .the ...

Error: Attempting to access property 'question' of an undefined value

Trying to render information from a local .json file using Javascript functions, I encountered an error in the console for const answer despite being defined. I temporarily commented it out to test the function, only to receive the same TypeError for quest ...

Utilize selenium IDE to retrieve a specific portion of text and save it as a variable

I am trying to figure out how to extract the number 694575 from a text using Selenium Ide and store it in a variable for future use. Here is the text I am working with: <div class="loginBoxTitle">Edit Exhibition Centre - 694575, Exhibition Center1&l ...

Differences between using Array.from and a for loop to iterate through an array-like object

When traversing an array-like object, which method is more efficient for performance: using Array.from( ).forEach() or a traditional for loop? An example of an array-like object would be: let elements = document.querySelector('#someid').children ...

Troubleshooting: Bootstrap 5 Submenu Dropdown Fails to Expand

I am struggling with implementing a dropdown menu in Bootstrap 5. Although the dropdown menu is visible, I am facing an issue where the submenu items do not expand upon clicking. Below is the code snippet that I am using: <body> <nav class=&qu ...

How can I save files to the ~/Documents directory using Node.js on my Mac computer?

Trying to work with the user's Documents folder in Node.js on macOS: var logger = fs.createWriteStream('~/Documents/somefolderwhichexists/'+title+'.txt'); Encountering an error without clear cause. Error message received: Unca ...