86

I'm building React components. I have added CSS inline in the components as suggested in this brilliant presentation by one of the guys 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?

Michael Johansen
  • 3,702
  • 2
  • 20
  • 34

7 Answers7

85

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.

Michael Johansen
  • 3,702
  • 2
  • 20
  • 34
  • Obligatory sorry for answering my own question. And thanks to @Vjeux for his answer. It worked really well! – Michael Johansen Feb 02 '15 at 01:34
  • 16
    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. – curly_brackets Apr 10 '15 at 06:27
  • 4
    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 – Ben Aug 30 '15 at 11:02
  • @Ben: I checked with Vjeux before posting this. Nowhere in this question or answer does it say that he said CSS was bad. Keep in mind that this solution will probably change as new builds of React are released. Until then I'm glad there is a solution (or in this case, workaround) that is simple and works well. – Michael Johansen Aug 31 '15 at 11:36
  • sorry for being a big sarcastic on my comment, but I was amazed to discover those thing were missing, and that he promoted this type use right here. I might just be lost in the state of React — production ready or experimental-in-progress-tool. waiting for new builds then – Ben Sep 01 '15 at 09:18
  • 3
    This is not a proper solution in my opinion. I use pseudo element like before and after to avoid creating unnecessary DOMs. – micky2be May 30 '16 at 07:37
  • There's a presentation by Vjeux in which he lists flaws of CSS and "fixes" them with React's inline styles. The whole "CSS sucks and our thing is great." nature of the presentation is very harmful and confuses a lot of newcomers. @KennethB's argument is valid and there are more valid arguments for using CSS with React. CSS has a nice, declarative syntax just like React, but using them together is harder than it needs to be and the team puts almost no effort into making it easier. I hope they eat the humble pie one day and fix these issues. Stopping the hate on CSS would be a nice first step. – AlicanC Aug 25 '16 at 17:13
  • I have been facing this issue from a long time I have a backgroundImage - .backgroundImageProp::after{ background-image: url('https://republic-prod.azureedge.net/republic-prod/stories/promolarge/xxhdpi/15207762165aa53418177b5.jpeg'); background-repeat: no-repeat; } I want to pass the background-image dynamically, I have tried lot of options -
    but didnt help, please let me know how can I achieve this, I am new to react
    – Praveen Pandey Mar 12 '18 at 14:25
  • 7
    This does not answer the question, creating a new element instead of useding pseudo elements is not a sufficient solution – Luke Flournoy Jun 25 '18 at 21:17
  • I had the same issue i was using the `-webkit-user-select: "text"​` then I saw react is not accepting this as a style so I found that i should use `webkitUserSelect` – Hidayat Arghandabi Feb 25 '20 at 10:34
36

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',
     '}'
    ].join('\n')
  }}>
</style>
<div className='my-special-div'></div>
Wiktor Kozlik
  • 683
  • 1
  • 6
  • 7
14

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

Joshua Robinson
  • 2,908
  • 1
  • 22
  • 35
10

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.

Peter W
  • 519
  • 5
  • 17
9

You can use styled components.

Install it with npm i styled-components

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

const YourEffect = 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 (
    <YourEffect>...</YourEffect>
  )
}

export default YourComponent
Raphael Pinel
  • 980
  • 12
  • 14
1

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);
Gaz Long
  • 317
  • 3
  • 13
-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.

ravibagul91
  • 16,494
  • 4
  • 24
  • 45
Stuart Aitken
  • 691
  • 10
  • 23
  • 4
    Question literally has nothing to do with TypeScript. – phillyslick Jun 28 '19 at 15:35
  • 1
    @phillyslick Yes it does. The given answer throws an error when written in Typescript. I provided a solution to that error. – Stuart Aitken Jun 29 '19 at 08:30
  • 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 Jul 02 '19 at 14:36
  • 1
    @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. – Stuart Aitken Jul 03 '19 at 03:49
  • 2
    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? – phillyslick Jul 03 '19 at 18:24