Styling the HTML content with the `css` prop

I’m testing how to apply CSS to the HTML that comes from WordPress.

The first way that may come to mind is to create a styled component and use a processor to add it:

const Styled1 = styled.a`
  color: blue;
`;

export const blockButtonStyled1 = {
  test: node =>
    node.component === "a" &&
    node.props.className.split(" ").includes("wp-block-button__link"),
  process: node => {
    node.component = Styled1;
    return node;
  }
};

The problem with this approach is that it makes impossible to add more styles to the wp-block-button__link after the first processor.

For example, this won’t work because node.component is not a anymore (it is Styled1):

const Styled2 = styled.a`
  background-color: yellow;
`;

export const blockButtonStyled2 = {
  test: node =>
    node.component === "a" &&
    node.props.className.split(" ").includes("wp-block-button__link"),
  process: node => {
    node.component = Styled2;
    return node;
  }
};

so you can either add the blue color or the yellow background, but not both.

To solve it, we can promote the usage of the css prop:

export const blockButtonCssProp1 = {
  test: node =>
    node.component === "a" &&
    node.props.className.split(" ").includes("wp-block-button__link"),
  process: node => {
    node.props.css = css`
      ${node.props.css};
      color: blue;
    `;
    return node;
  }
};

This processor adds the color blue, but the node.component is not modified and can be found by another processor executed later:

export const blockButtonCssProp2 = {
  test: node =>
    node.component === "a" &&
    node.props.className.split(" ").includes("wp-block-button__link"),
  process: node => {
    node.props.css = css`
      ${node.props.css};
      background-color: yellow;
    `;
    return node;
  }
};

Now, your wp-block-button__link has both a blue color and a white background.

You can also control which CSS takes precedence by positioning the ${node.props.css} before or after your CSS:

node.props.css = css`
  ${node.props.css};
  background-color: yellow;  // <-- this will overwrite node.props.css
`;
node.props.css = css`
  background-color: yellow;  // <-- this won't overwrite node.props.css
  ${node.props.css};
`;

Apart from that, I’m not sure how’s the best way to propose, if using node.props.css inside the css props or using an array like this:

const blue = css`
  color: blue;
`;

export const blockButtonCssProp1 = {
  test: node =>
    node.component === "a" &&
    node.props.className.split(" ").includes("wp-block-button__link"),
  process: node => {
    node.props.css = [node.props.css, blue];
    return node;
  }
};

That’s great @luisherranz! Thanks for the analysis :slightly_smiling_face:

It seems that adding it using the css prop is the right approach.

I guess this will depend in each case, but I’d recommend using an array. I think it will be cleaner sometimes. Although I know it’s different, it similar to the way it’s done in the twentytwenty theme.

A simple helper can be created to facilite the task:

const cssProcessor = (component, className, css) => ({
  test: node =>
    node.component === component &&
    node.props.className.split(" ").includes(className),
  process: node => {
    node.props.css = [node.props.css, css];
    return node;
  }
});

And then:

const blue = css`
  color: blue;
`;

const yellowBg = css`
  background-color: yellow;
`;

export const blueButton = cssProcessor("a", "wp-block-button", blue);
export const yellowBgButton = cssProcessor("a", "wp-block-button", yellowBg);

I do like the cleanliness of the array, but I also think it’s counter-intuitive and might be confusing for people. But if it’s the way promoted by Frontity and people can find examples written this way in the docs, it shouldn’t be a problem.

It would be nice to have such utility in html2react. I think it would be nice to write it in a way that behaves like Document.querySelector(). So I could write:

export blueButton = createCssProcessor('a.wp-block-button', blue);
export greenButton = createCssProcessor('#accept', green);
export yellowButton = createCssProcessor('input[type="submit"]', yellow);

I really like that idea!

Maybe it can be added to the node instead of node.hasClass:

{
 test: node => node.is(".wp-block-button"),
 test: node => node.is("a.wp-block-button"),
 test: node => node.is("#accept"),
 test: node => node.is('input[type="submit"]'),
}

I’ve added it to this feature topic: Better class name tests in processors
Please continue the conversation about it in that topic.

3 Likes

My only concern (I’m working right now in the frontity/frontity.org#2 feature) is how to access to the state from the css prop.

I rembeber that we had a conversation about this but I don’t remember the conclusions. :sweat_smile: Did we finally add the ThemeProvider that exposes emotion-theming?

I think we didn’t (not shure about that).

No, we didn’t because it was not clear.

Ok, we need to think about a solution to access state in processors then, right?

This is the relevant Feature Discussion: Theming

Great, thanks. :+1:

I’m going to open a Feature Discussion for Accessing state inside a processor.

We can use state inside processors now: Access state inside a processor :clap:

2 Likes