I need to isolate styles of widget script, I'm working on from the main site, where the widget script is getting injected.
The widget script uses react with tailwind css (with extended theme) and Rhythm UI library (also, uses tailwind css underneath). The target site also uses the same structure. That's why when the css overlaps, it's taking the widget's css.
To overcome the problem, I have tried iframe approach, shadow dom approach, minifying css using mini-css-extract-plugin with webpack but nothing works as expected.
Shadow DOM and iframe produces similar results where the elements not at all get the styling. it displays as simple html component, in case of iframe, the click events didn't worked as well. PS: tried Shadow DOM with vanila js and react-shadow library and iframe with react-frame-component
import Frame from 'react-frame-component';
.
.
<Frame head={<link type='text/css' rel='stylesheet' href='../styles.css' />}>
<App />
</Frame>
Also, tried this way with shadow dom, Shadow root is coming empty:
import React, { useLayoutEffect } from "react";
import { createRoot } from "react-dom/client";
import { createPortal } from "react-dom";
import { App } from "./app";
import styles from "!!raw-loader!./style.css";
import css from "!!raw-loader!../index.css";
const host = document.getElementById("codemonk");
const ShadowApp = () => {
return (
<>
<App />
<style type="text/css">{styles}</style>
<style type="text/css">{css}</style>
</>
);
};
const AppWithShadow = () => {
const shadowRoot = host.attachShadow({ mode: "open" });
useLayoutEffect(() => {
createPortal(<ShadowApp />, shadowRoot);
}, [shadowRoot]);
return null;
};
createRoot(host).render(<AppWithShadow />);
Used webpack to minify css, I have used below configuration:
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
...
module.exports = {
...
plugins: [
new MiniCssExtractPlugin({
filename: "index.css",
chunkFilename: "index.css",
})
],
module: {
rules: [
{
test: /\.css$/
use: [
MiniCssExtractPlugin.loader,
'css-loader',
'postcss-loader'
]
}
]
}
}
This way, the elements were inherited the target site's theme and did not applied the tailwind css classes applied to it.
On other hand, I have also tried isolation css property on root element, like this:
#rootEl {
isolation: isolate;
}
I have only get partial success, when I added important option to the tailwind.config.cjs file like this:
important: '#uniqueId'
Here, the core tailwind css styles are kept intact with widget and site but the extended theme was prioritised on the sites styling over it's own.
Edit: Somehow I made the shadow dom approach work but it only works with pure react components. It throws error if hooks are used.
Warning: Invalid hook call. Hooks can only be called inside of the body of a function component. This could happen for one of the following reasons:
1. You might have mismatching versions of React and the renderer (such as React DOM)
2. You might be breaking the Rules of Hooks
3. You might have more than one copy of React in the same app