121

I'm building React components. I have added CSS inline in the components as suggested in this brilliant presentation by one of the people behind React. I've been trying all night to find a way to add CSS pseudo classes inline, like on the slide titled "::after" in the presentation. Unfortunately, I do not just need to add the content:""; property, but also position:absolute; -webkit-filter: blur(10px) saturate(2);. The slides show how to add content through {/* … */}, but how would you add other properties?

8 Answers 8

109

Got a reply from @Vjeux over at the React team:

Normal HTML/CSS:

<div class="something"><span>Something</span></div>
<style>
    .something::after {
    content: '';
    position: absolute;
    -webkit-filter: blur(10px) saturate(2);
}
</style>

React with inline style:

render: function() {
    return (
        <div>
          <span>Something</span>
          <div style={{position: 'absolute', WebkitFilter: 'blur(10px) saturate(2)'}} />
        </div>
    );
},

The trick is that instead of using ::after in CSS in order to create a new element, you should instead create a new element via React. If you don't want to have to add this element everywhere, then make a component that does it for you.

For special attributes like -webkit-filter, the way to encode them is by removing dashes - and capitalizing the next letter. So it turns into WebkitFilter. Note that doing {'-webkit-filter': ...} should also work.

Sign up to request clarification or add additional context in comments.

10 Comments

Obligatory sorry for answering my own question. And thanks to @Vjeux for his answer. It worked really well!
But, as React JS is rendered out to search agents, they will index the pseudo content, which isn't good. If you, for example, copy a headline into a ::after-element, to create a custom shadow, just for styling purposes I wouldn't be in the DOM when Google sees it, but with this approach, Google will see it... Meaning you will have two headlines.
Too bad this pops-up on top when you search for pseudo-elements in react. @vjeux might be quite annoyed to have said that css was bad, without actually providing a clean/complete alternative to its react-followers. This solution should not be accepted, it is a step backward — btw sure it did work really well ahah
This is not a proper solution in my opinion. I use pseudo element like before and after to avoid creating unnecessary DOMs.
This does not answer the question, creating a new element instead of useding pseudo elements is not a sufficient solution
|
52

Inline styles cannot be used to target pseudo-classes or pseudo-elements. You need to use a stylesheet.

If you want to generate CSS dynamically, then the easiest way is to create a DOM element <style>.

<style
  dangerouslySetInnerHTML={{
    __html: `
      .my-special-div:after {
        content: "Hello";
        position: absolute
      }
    `
  }}
></style>
<div className="my-special-div"></div>

1 Comment

Nice. Even better would be to just use a template string with literal newlines so you don't need to join a bunch of individual strings.
31

Depending if you only need a couple attributes to be styled inline you can do something like this solution (and saves you from having to install a special package or create an extra element):

https://stackoverflow.com/a/42000085

<span class="something" datacustomattribute="👋">
  Hello
</span>
.something::before {
  content: attr(datascustomattribute);
  position: absolute;
}

Note that the datacustomattribute must start with data and be all lowercase to satisfy React.

3 Comments

Also note that, whilst it has to be lowercase, it can also include dashes, e.g. data-custom-attribute works too
As of July 2021, as stated in MDN docs: The attr() function can be used with any CSS property, but support for properties other than content is experimental, and support for the type-or-unit parameter is sparse.
works well with react
16

Inline styling does not support pseudos or at-rules (e.g., @media). Recommendations range from reimplement CSS features in JavaScript for CSS states like :hover via onMouseEnter and onMouseLeave to using more elements to reproduce pseudo-elements like :after and :before to just use an external stylesheet.

Personally dislike all of those solutions. Reimplementing CSS features via JavaScript does not scale well -- neither does adding superfluous markup.

Imagine a large team wherein each developer is recreating CSS features like :hover. Each developer will do it differently, as teams grow in size, if it can be done, it will be done. Fact is with JavaScript there are about n ways to reimplement CSS features, and over time you can bet on every one of those ways being implemented with the end result being spaghetti code.

So what to do? Use CSS. Granted you asked about inline styling going to assume you're likely in the CSS-in-JS camp (me too!). Have found colocating HTML and CSS to be as valuable as colocating JS and HTML, lots of folks just don't realise it yet (JS-HTML colocation had lots of resistance too at first).

Made a solution in this space called Style It that simply lets your write plaintext CSS in your React components. No need to waste cycles reinventing CSS in JS. Right tool for the right job, here is an example using :after:

npm install style-it --save

Functional Syntax (JSFIDDLE)

import React from 'react';
import Style from 'style-it';

class Intro extends React.Component {
  render() {
    return Style.it(`
      #heart {
        position: relative;
        width: 100px;
        height: 90px;
      }
      #heart:before,
      #heart:after {
        position: absolute;
        content: "";
        left: 50px;
        top: 0;
        width: 50px;
        height: 80px;
        background: red;
        -moz-border-radius: 50px 50px 0 0;
        border-radius: 50px 50px 0 0;
        -webkit-transform: rotate(-45deg);
        -moz-transform: rotate(-45deg);
        -ms-transform: rotate(-45deg);
        -o-transform: rotate(-45deg);
        transform: rotate(-45deg);
        -webkit-transform-origin: 0 100%;
        -moz-transform-origin: 0 100%;
        -ms-transform-origin: 0 100%;
        -o-transform-origin: 0 100%;
        transform-origin: 0 100%;
      }
      #heart:after {
        left: 0;
        -webkit-transform: rotate(45deg);
        -moz-transform: rotate(45deg);
        -ms-transform: rotate(45deg);
        -o-transform: rotate(45deg);
        transform: rotate(45deg);
        -webkit-transform-origin: 100% 100%;
        -moz-transform-origin: 100% 100%;
        -ms-transform-origin: 100% 100%;
        -o-transform-origin: 100% 100%;
        transform-origin :100% 100%;
      }
    `,
      <div id="heart" />
    );
  }
}

export default Intro;

JSX Syntax (JSFIDDLE)

import React from 'react';
import Style from 'style-it';

class Intro extends React.Component {
  render() {
    return (
      <Style>
      {`
        #heart {
          position: relative;
          width: 100px;
          height: 90px;
        }
        #heart:before,
        #heart:after {
          position: absolute;
          content: "";
          left: 50px;
          top: 0;
          width: 50px;
          height: 80px;
          background: red;
          -moz-border-radius: 50px 50px 0 0;
          border-radius: 50px 50px 0 0;
          -webkit-transform: rotate(-45deg);
          -moz-transform: rotate(-45deg);
          -ms-transform: rotate(-45deg);
          -o-transform: rotate(-45deg);
          transform: rotate(-45deg);
          -webkit-transform-origin: 0 100%;
          -moz-transform-origin: 0 100%;
          -ms-transform-origin: 0 100%;
          -o-transform-origin: 0 100%;
          transform-origin: 0 100%;
        }
        #heart:after {
          left: 0;
          -webkit-transform: rotate(45deg);
          -moz-transform: rotate(45deg);
          -ms-transform: rotate(45deg);
          -o-transform: rotate(45deg);
          transform: rotate(45deg);
          -webkit-transform-origin: 100% 100%;
          -moz-transform-origin: 100% 100%;
          -ms-transform-origin: 100% 100%;
          -o-transform-origin: 100% 100%;
          transform-origin :100% 100%;
        }
     `}

      <div id="heart" />
    </Style>
  }
}

export default Intro;

Heart example pulled from CSS-Tricks

1 Comment

style-it is not maintained. Don't install.
13

You can use styled components.

Install it with npm i styled-components

import React from 'react';
import styled from 'styled-components';

const ComponentWithPseudoClass = styled.div`
  height: 50px;
  position: relative;
  &:after {
    // whatever you want with normal CSS syntax. Here, a custom orange line as example
    content: '';
    width: 60px;
    height: 4px;
    background: orange
    position: absolute;
    bottom: 0;
    left: 0;
  }
`;

const YourComponent = props => {
  return (
    <ComponentWithPseudoClass>...</ComponentWithPseudoClass>
  )
}

export default YourComponent

Comments

5

I don't know if this would be considered hacky but it certainly works (using CSS variable):

const passedInlineStyle = { '--color':'blue'}

Then in an imported CSS file:

background:var(--color);

Comments

0

The easiest trick is to add '""' instead of '' in the content property for the pseudo-element.

const styles = {
    container: {
        // ... Container styling

        '&::after': {
            display: 'block',
            content: '""'
        }
    }
};

Comments

-2

Not a direct answer to the question, but this may help those who are having trouble creating style information using Typescript.

I was getting an error telling me that the following was incorrect:

let iconStyle = {
    position: 'relative',
    maxHeight: '90px',
    top: '25%',
}

The error told me that "types of property 'position' are incompatible". I have no idea why.

I fixed this by adding a strict Typescript declaration, like so:

let iconStyle: CSSProperties = {
    position: 'relative',
    maxHeight: '90px',
    top: '25%',
}

This works.

5 Comments

Question literally has nothing to do with TypeScript.
@phillyslick Yes it does. The given answer throws an error when written in Typescript. I provided a solution to that error.
Your answer is about how to type CSS properties, specifically a position property type and why you can't use a string. There are a few solutions to this (and you suggest a good one), but again, this question isn't about TypeScript. It's about JavaScript and React and CSS. No one coming here should think TypeScript has anything to do with this question or its given solution.
@phillyslick Surely you're aware of how much overlap Javascript and Typescript have? There are countless times I (and surely others) have searched for solutions to issues when working with React, and found a solution written in Javascript which works just as well in Typescript. Sometimes however, such as the above, this isn't the case. For me to add a note with a small tweak to make the above solution work for those who came here with React CSS issues in Typescript is hardly a leap into the arbitrary. I don't see at all what your big problem is here to be honest.
My "big problem" is that your answer isn't helpful to someone not using TypeScript. Currently, your answer sits above the accepted answer. However, it doesn't answer the question - you say so yourself. It answers a possible issue some users may have which is tangential to the question. What happens when someone is using SASS in their pipeline, should we answer that, too? What about React Native? One could argue that's as tangential to React as TypeScript. See my point?

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.