21

I am using styled-components and want to target the first child of Text, but am unable to do so.

const Text = styled.p`
    font-size: 12px;
    &:first-child {
        margin-bottom: 20px;
    }
`;

... component

return(
   <div>
      <p>I am just regular text</p>
      <p>Me too</p>
      <Text>Hello Joe</Text> // this should have the margin bottom
      <Text>Goodbye</Text >
   </div>
)
peter flanagan
  • 9,195
  • 26
  • 73
  • 127

5 Answers5

31

Finally, I got your issue. The styled component confuses with the first two native p tag (from my perspective) and that's the reason why the CSS is not applied.

I will use a workaround like this:

const Text = styled.p`
    font-size: 12px;
    color: blue;
    &:nth-child(3) {
        margin-bottom: 20px;
        color: red !important;
    }
`;

By doing this, you are selecting the third child (which include the first two p tag) for the CSS

OR, you can do something like this: Adding a class name for the tag and giving CSS for that class.

const Text = styled.p`
  font-size: 12px;
  color: blue;
  &.colors {
    margin-bottom: 20px;
    color: red !important;
  }
`;

 <div>
    <p>I am just regular text</p>
    <p>Me too</p>
    <Text className="colors">Hello Joe</Text>
    <Text>Goodbye</Text>
</div>

Here is the demo

Hope it helps :)

Arun AK
  • 4,353
  • 2
  • 23
  • 46
  • I updated my question slightly, there is a `span` within the `p` tag, would that have something to do with it not working? Sorry for not including earlier. Also, when I use your code it is all in blue, so for some reason first-child not working – peter flanagan Jan 02 '19 at 15:36
  • so strange, still not working for me here. Will give ye both upvotes anyway – peter flanagan Jan 02 '19 at 15:45
  • @Thinker lol I've written almost the exact same words and also provided a demo using two different colors. I think we might be css-soulmates,.. just kidding.. :D – dschu Jan 02 '19 at 16:27
  • can you check the updated question - this is why it is off – peter flanagan Jan 02 '19 at 23:18
  • @peterflanagan you are correct. Now I am getting the issue. It's becz of the first two `p` tag. I have updated my solutions. Hope it helps :) – Arun AK Jan 03 '19 at 00:07
20

Use like this

const Text = styled.p`
   font-size: 12px;
    > * {
      &:first-child {
         margin-bottom: 20px;
      }
    }
`;
wscourge
  • 10,657
  • 14
  • 59
  • 80
Dagar
  • 201
  • 2
  • 2
10

There shouldn't be a space between the & and the :first-child

&:first-child {
    margin-bottom: 20px;
}
dan
  • 1,198
  • 8
  • 25
4

it's better to use :last-of-type on certain styled component instead of using :nth-child and it works perfectly

export default styled.div`
    :last-of-type {
        background: red;
    }`

const Text = styled.p`
    font-size: 12px;
    color: blue;
    &:nth-child(3) {
        margin-bottom: 20px;
        color: red !important;
    }
`;
kuubson
  • 155
  • 1
  • 3
  • I like the `last-of-type` approach. A little more modular (e.g. component styling is kept specific to the element itself, rather than interfering with a child). – vincent Apr 01 '22 at 16:37
0

This is possible, but probably not correct

This totally is possible, as we see with the other answers. The issue is that with first-child or nth-child solutions you tend to end up reaching down the DOM hierarchy, creating all sorts of specificity issues that can be difficult to untangle later.

The beauty of Styled Components is you typically apply styles to the element itself, meaning your styles stay tightly coupled to your components. Components become portable, and it's easy to find the line of CSS that might be causing an issue in a complex app.

for example, if I were to style the first <a> in a list item in a ul differently, I'd need to put :first-child further up the hierarchy, breaking encapsulation.

Treat your styles as a function

The simple solution to this is to recognise that the styled component is a function that can receive parameters:

<StyledListItem index={index} />

Then receive that parameter in the component:

export const StyledListItem = styled.li<{index?: number}>`
  ${
    ({index}) => {
      if (index === 3) return `
        color: red;
        border: 2px dotted pink;
      `
      if (index === 0) return `
        border-left: none
      `
    }
  }
`

CSS in JS facilitates these kinds of programmatic solutions, and your life will be easier if you leverage them.

superluminary
  • 47,086
  • 25
  • 151
  • 148