Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Strategy for associating styles to components rather than at the parent level? #57

Open
kprokopczyk opened this issue Feb 11, 2021 · 15 comments
Labels
question Further information is requested

Comments

@kprokopczyk
Copy link

kprokopczyk commented Feb 11, 2021

I have a base template component that i pass my components to and render them inside MjmlBody:

const BaseEmailTemplate = ({ children }) => {
    const styles = readFileSync(resolve(__dirname, '../../assets/styles.css')).toString();
    const mediaQueryStyles = readFileSync(resolve(__dirname, '../../assets/mediaQueries.css')).toString();

    return (
        <Mjml>
            <MjmlHead>
                <MjmlStyle inline>{styles}</MjmlStyle>
                <MjmlStyle>{mediaQueryStyles}</MjmlStyle>
            </MjmlHead>
            <MjmlBody>
                {children}
            </MjmlBody>
        </Mjml>
    );
};

So I'm reading in css files and rendering the styles in MjmlHead, much like your example. For media queries, each of my templates includes ALL the styles, even styles targeted to components that a given template does not include. Since some email clients clip emails over a certain size, I want to only include styles that are relevant to the components included in a given template. Additionally, if I delete a component I want all its style definitions to go with it.

I'm wondering if you have any strategies for moving css to the component level so that only the styles associated with the children are rendered in head. Like ideally i'd like my components organized like this, with css tied to each component:

components/
    BaseEmailTemplate/
        BaseEmailTemplate.jsx
        index.js
        styles.css 
    Button/
        Button.jsx
        index.js
        styles.css

Thanks for any tips.

@kprokopczyk kprokopczyk changed the title Strategy for associating styles to components rather than at the parent component level? Strategy for associating styles to components rather than at the parent level? Feb 11, 2021
@IanEdington
Copy link
Contributor

IanEdington commented Feb 11, 2021

So I'm reading in css files and rendering the styles in MjmlHead, much like your example.

What example are you referring to? We have been talking about how to solve this problem as well and are planning on taking the approach that styled-components uses for render to string... just haven't had a chance to implement yet

A possible solution to your issue would be to use a post processor on the html. Something like https://emailcomb.com/

@kprokopczyk
Copy link
Author

The example I'm referring to is just this, where a file is read in: https://github.com/wix-incubator/mjml-react-example/blob/master/src/email.js#L18

A post processor feels like a good stopgap but it still doesn't allow me to couple styles with components, so I'll probably keep looking around for a good solution. Thanks!

@IanEdington
Copy link
Contributor

yeah agreed. Same reason we aren't doing it

@IanEdington
Copy link
Contributor

IanEdington commented Feb 15, 2021

@kprokopczyk we've started using https://github.com/styled-components/styled-components with mjml-react.

This is our "react to mjml" script:

import React from "react";
import ReactDOMServer from "react-dom/server";
import { ServerStyleSheet } from "styled-components";

function getStyledComponentsStaticCss(sheet: any): string {
  const tag = sheet.getTag();

  return [...Array(tag.length).keys()].map((group) => tag.getGroup(group)).join("");
}

export function getMjmlFromReact(element: React.ReactNode) {
  const sheet = new ServerStyleSheet();
  const elementWithCollectedStyles = sheet.collectStyles(element);
  const mjmlWithoutStyledComponentsCss = ReactDOMServer.renderToStaticMarkup(elementWithCollectedStyles);
  const css = getStyledComponentsStaticCss(sheet.instance);
  return mjmlWithoutStyledComponentsCss.replace(/\/\* inject css here \*\//g, css);
}

How to use styled components:

const StyledMjmlText = styled(({className, ...props}) => <MjmlText {...props} cssClass={className} />)`
  height: 250px;
  border: 1px solid red !important;
`;

export const TestingStyles: Story = () => (
  <Mjml>
    <MjmlHead>
      <MjmlStyle>
        {css`
          /* inject css here */
        `}
      </MjmlStyle>
    </MjmlHead>
    <MjmlBody>
      <MjmlSection>
        <MjmlColumn>
          <StyledMjmlText>Hello 250px high typography</StyledMjmlText>
        </MjmlColumn>
      </MjmlSection>
    </MjmlBody>
  </Mjml>
);

This works with deeply nested components. Unfortunately it requires className => css-class which is a little cumbersome.

Based on this repo having basically no support. I'm thinking about just implementing my own version with a bunch more functionality like className => css-class

@gajus
Copy link

gajus commented Apr 15, 2021

@IanEdington Did you end up developing / open-sourcing anything to help with styled-components adoption?

@IanEdington
Copy link
Contributor

@gajus not yet but I could... let me get back to you

@gajus
Copy link

gajus commented Apr 21, 2021

I would appreciate that. I spent couple of hours playing with styled-components and Mjml and couldn't make it work.

@IanEdington
Copy link
Contributor

@gajus I got the go ahead to open source a couple of our mjml tools. I should be able to get them up early next week

@gajus
Copy link

gajus commented Apr 26, 2021

@gajus I got the go ahead to open source a couple of our mjml tools. I should be able to get them up early next week

Please ping in this thread if / when you share those tools. 🙏

@IanEdington
Copy link
Contributor

Sorry for the delay on this. I'm trying to prioritize this work.

@gajus
Copy link

gajus commented May 3, 2021

Sorry for the delay on this. I'm trying to prioritize this work.

Any chance you could share whatever MVP you've got, even it isn't polished?

@matepaiva
Copy link

@IanEdington please let us know when you share this! <3 Thank you!

@gajus
Copy link

gajus commented Jun 22, 2021

@IanEdington Any luck?

@daliusd daliusd added the question Further information is requested label Feb 28, 2022
@IanEdington
Copy link
Contributor

Hey all, sorry for leaving you hanging. We have support for this in https://github.com/Faire/mjml-react version 3+

This issue has a short overview of how we use style-components Faire/mjml-react#70

TLDR: We've added className -> cssClass so any react tool that uses className can be used with mjml-react

@matepaiva
Copy link

Amazing! Thanks @IanEdington!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
question Further information is requested
Projects
None yet
Development

No branches or pull requests

5 participants