Reputation: 49974
My app tries to show emails. Sometimes the style in the email will affect the app itself.
Right now I am using the package juice to inline style in the email html. However, sometimes it cannot inline correctly. So I try to find other solutions.
I know Angular automatically add some random string in each class to make sure style in one component won't affect other component, is there a same way to do it in React? Or is there other way to limit style to the component level without using iframe? Thanks
The demo shows the p { color: red; }
from the email also affects the app itself. In this case, it affects Content in app
.
class Mail extends Component {
render() {
// the style inside is from mail, in real case, it can have tens or even hundreds of different styles
const mailFromServer = `
<html>
<head>
<style>
p { color: red; }
</style>
</head>
<body>
<p>Content in mail</p>
</body>
</html>
`;
return (
<div>
<div dangerouslySetInnerHTML={{__html: mailFromServer}} />
</div>
);
}
}
class App extends Component {
render() {
return (
<div>
<Mail />
<p>Content in app</p>
</div>
);
}
}
Upvotes: 9
Views: 4929
Reputation: 1991
Even though browser support is not great (48%) at the moment for @scope, it can be used to selectively target ancestor subtrees. For example, in this JSFiddle (please run in Chrome November 2023 due to browser support limitations), you can see that the .target
sub-tree is selected for:
p {
color: red;
font-size: 24px
}
@scope (.target) {
p {
color: green
}
}
In your demo case above, try using @scope
like this:
class Mail extends Component {
render() {
const mailFromServer = `
<html>
<head>
<style>
@scope (.target) { // added @scope
p { color: red; }
}
</style>
</head>
<body class=target> <!-- added scoping class -->
<p>Content in mail</p>
</body>
</html>`;
return (
<div>
<div dangerouslySetInnerHTML={{__html: mailFromServer}} />
</div>
);
}
}
UPDATE May 2024:
With good browser support (75%) in May of 2024, the @scope
rule is well suited for your use case. For example, here is an example from one of my React apps (attached), where the
@scope
rule has been applied to #journal-section only (giving this input field a bold, red text style.
Input fields of other components retain their specific text style and do NOT take on @scope
style.
Upvotes: 0
Reputation: 1403
Yes, you can use CSS Modules, which is one or more css files (written in js) in which all class names are auto-scoped locally to each component by default.
There is a good article about this here https://medium.com/@pioul/modular-css-with-react-61638ae9ea3e
You can also try to reset those known html entities which are commonly over-ridden by your Mail html. You may have to play around a bit, but, given your example, you could do something like the following:
https://stackblitz.com/edit/react-neymbb
Basically, in my sandbox I reset your paragraph color and padding to their defaults, as well as, used it in conjunction with another inline style. Depending on the entire construct of css inheritance in your app, your results may vary, but you should be able to get something workable.
More information on the css values I recommend found here: https://developer.mozilla.org/en-US/docs/Web/CSS/initial
Upvotes: 0
Reputation: 175
There are few ways to do this.One of the way would be by passing style
to the elements and defining styles as objects. For example
const styles = {
content: {
color: '#000',
backgroundColor: '#fafafa',
},
};
class Mail extends React.Component {
render() {
return() {
<p style={{styles.content}}> Content </p>
}
}
}
If you really want something scalable then you can use styled-components which for me personally work really nicely and fulfills all your styling needs.
Upvotes: 3
Reputation: 2705
Styles in <style>..</style>
or from CSS sheet is global. They are applied across your app.
If you have control over how the email is formatted, I would recommend setting different class names for different email types.
If you have a limited set of email types, you can specify the styles for each of them in a css sheet, and import it on your html file or Webpack.
styles.css
.important-email { color: red; }
.not-important-email { color: blue; }
// ...
// styles for different email types
Mail.jsx
class Mail extends Component {
render() {
const mail = `
<html>
<head>
</head>
<body>
<h1 class="important-email">Heading in mail</h1>
</body>
</html>
`;
return (
<div>
<div dangerouslySetInnerHTML={{__html: mail}} />
</div>
);
}
}
export default Mail;
Upvotes: 0
Reputation: 4921
You'll need to use a class to limit the style to a specific component's features:
import React, { Component } from 'react';
import { render } from 'react-dom';
class Mail extends Component {
render() {
const mail = `
<html>
<head>
<style>
.mail-header { color: red; }
</style>
</head>
<body>
<h1 class="mail-header">Heading in mail</h1>
</body>
</html>
`;
return (
<div>
<div dangerouslySetInnerHTML={{__html: mail}} />
</div>
);
}
}
export default Mail;
Upvotes: 0