0

I'm new to React and anything other than early 2000's Javascript (hell I'm new to all this UI), and the fact that I'm not finding an answer implies I'm approaching this the wrong way. So I'd appreciate someone showing me the light and/or telling me how to accomplish what I'm trying to do!

In short, I have one component X that has a few instances of another component Y. I'm trying to add css to the parent component that will apply to all of the Ys (specifically, a margin in my use case. Notably, I want to apply this styling only to these instances of Y inside my X, not to every Y on the page. I understand that I can't override specified styles in Y from the parent, but I am trying to add a style that is not specified on Y.

More concretely:

Metrics.js (shortened):

import './Metrics.css'

class Metrics extends Component {
  render() {
    return (
      <div className="Metrics">
        <div className="titlebar">
          <div>Metrics</div>
          <Button>...</Button>
          <Button>...</Button>
        </div>
      </div>
    );
  }
}

Metrics.css

.titlebar {
  ...
}

.titlebar Button {
  padding: 10px;
}

I believe Button does not work as a selector since that's not the html that actually gets generated. So if Button were a component I owned, and I could modify it to have a root <div className="Button"> then I believe could use

.titlebar .Button {...}

But in this case I am importing Button (from material-ui), so I don't have control over this. I could find out what it happens to render but to my knowledge this is not guaranteed by contract so it would be fragile to depend on that observation.

So is there a way to apply a css selector, or something similar, to a React component by name or some other method of identifying the React component?

I'm looking for a general solution: I don't want to solve this for Button but for any React component I might build or import and use in the same way. E.g. I've already run across the same issue for the FontAwesome component, also imported. Even for components I own, I feel that it's introducing unnecessary tight coupling to depend on a convention that the class on the root element includes the component name. Is there a more generalized and robust way to accomplish this?

1
  • 1
    I suggest you do a research about CSS-in-JS approaches. A good place to start is styled-components.com. This gives you an idea on either how to use styled components and totally forget about using CSS as separate files or how to properly pass conditional class names as props. Also you can read about React context API to find out how to apply themes. Commented Feb 25, 2019 at 22:04

2 Answers 2

1

You can set class for buttons, and set style by class

<Button className="button">...</Button>

.titlebar .button {
  padding: 10px;
}
Sign up to request clarification or add additional context in comments.

2 Comments

I knew I was missing something that simple. I think this was a case of "tried it, didn't work because of a typo or other bug, assumed it didn't work in general"
Confirmed the reason I didn't see it working was that padding and margin are set by the component (margin to 0px). So when I tried adding my own margin it was being overwritten by that native to the component. So I ended up wrapping it in a div that I could apply my own margin to.
0

In your Button component add a prop with something you can use to conditionally add a class name via ES6 string interpolation. For example:

const Button = ({type}) => {
   return (
     <button className=`button-${type}`>
       I'm a button
     </button>
   )
}

Utilize a stylesheet for your various class names

.button-red {
  background: red;
}

.button-blue {
  background: blue;
}

.button-margin-left {
  margin-left: 2em;
}

Pass the prop into <Button>

<Button type='margin-left' />
<Button type='blue' />
<Button type='red' />

I believe this should suit your needs

1 Comment

But I can't do that for components that I'm importing (without forking the source code), which is the crux of the problem. I suppose along these lines could create a simple <div> wrapper around the imported button. Seems like a lot of code for something native css has solved, but maybe I need to change my perspective.

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.