Search code examples
javascriptcssreactjspostcss

Reset `!important` CSS and allow styling with JS


I am building a React widget that will be embedded directly on third-party sites. I would like to completely reset the CSS applied to my widget's container <div>, such that it's not affected by the host site's CSS (including !important). The project uses React, Webpack, CSS modules, and a few PostCSS plugins.

My CSS modules setup does create unique, private CSS names which should not collide with the host site's CSS. However, this doesn't protect against host site CSS that e.g. just selects all buttons.

To account for this, I've been using Cleanslate as a reset stylesheet, which uses all !important rules. This successfully prevents CSS from the host site from being applied. However, in order to apply my own CSS on top of Cleanslate, I have to use !important on all of my CSS and increase the specificity of my CSS. I am using PostCSS plugins to do both.

However, I also want to set some styles in React. I had been adding inline styling to my DOM elements (e.g. style={{ color: "red" }}). However, since I'm adding !important to all of my CSS, these inline styles are always overridden by my other CSS.

Besides Cleanslate:

  • I looked at all: unset, but ran into the same problem as Cleanslate -- to override !important CSS, I have to use !important in all of my CSS.
  • I also considered a CSS-in-JS solution like styled-components, but styled-components at least doesn't have an easy way to always apply !important (you can increase specificity with &&&, but that doesn't override !important).

Any advice on changes to my current CSS/JS setup or another setup that would accomplish this would be much appreciated. (Maybe very far-reaching !important host site CSS is just too small of an edge case to worry about though.) Thank you!

TL;DR: React widget on third-party sites. I want to override the host site's CSS (including !important) but also be able to set styles with JS.


Solution

  • Top technology up till Shadow dom, was <iframe>, but it is a pain to configure outside or make some smart behavior.

    Take a look at Shadow dom: https://developer.mozilla.org/en-US/docs/Web/Web_Components/Using_shadow_DOM

    Shadow dom is a very cool vanilla feature that allows you to create web components. Under the hood, Angular uses it also.

    Once in the past, I have built a widget myself. And went through all the options, but in the end, I found out that the best solution is shadow dom and JivoChat does something like this by creating its own elements like <jdiv> which will allow you to encapsulate and style your widget safely.

    Check JivoChat: https://www.jivochat.com/