1

I have a component like this:

// MyComponent.tsx
export function MyComponent(): React.ReactElement {
  return <Wrapper>
           <Text>
             hello there
           </Text>
           <AnotherText>
             bye bye
           </AnotherText> 
         </Wrapper>
} 

export const Wrapper = styled.div`
  color: #FEB240;
  background: #f5f5f5;
  padding-bottom: 5rem;
  padding-left: 7rem;
  padding-right: 7rem;
  gap: 2rem;
`;

export const Text = styled.span`
  width: 50%;
  cursor: pointer;
  color: rgba(28, 33, 120, 1);
`;

export const AnotherText = styled.span`
  color: red;
`;

I want to be able to style the wrapper. I tried to like this (from this answer Styling Nested Components in Styled-Components), but I don't see any change:

// AnotherPlace.tsx
const NewlyStyledMyComponent = styled(MyComponent)`
  ${Wrapper} {
    color: brown;
    background: magenta;
   }
`;
ghybs
  • 47,565
  • 6
  • 74
  • 99
Avba
  • 14,822
  • 20
  • 92
  • 192

2 Answers2

1

It seems that MyComponent also need to take (generated) className as props and assign it to the root wrapping element to make the nested styles to work as expected.

Simplified live demo: stackblitz

A basic example in MyComponent:

import styled from 'styled-components';

interface Props {
  className?: string;
}

export const Wrapper = styled.div`
  background-color: hotpink;
`;

export const Text = styled.span`
  color: #fff;
`;

function MyComponent({ className }: Props) {
  return (
    <div className={className}>
      <Wrapper>
        <Text>Hello</Text>
      </Wrapper>
    </div>
  );
}

export default MyComponent;

And at where it is imported and used:

import styled from 'styled-components';
import MyComponent, { Wrapper, Text } from './MyComponent';

const NewlyStyledMyComponent = styled(MyComponent)`
  margin-bottom: 7px;
  ${Wrapper} {
    background-color: indigo;
  }
  ${Text} {
    color: gold;
  }
`;

function App() {
  return (
    <div>
      <NewlyStyledMyComponent />
      <MyComponent />
    </div>
  );
}

export default App;
John Li
  • 6,976
  • 3
  • 3
  • 27
0

There are indeed 2 issues:

  1. To style a custom React component (even just so that its nested components can be styled), you always need to take a className prop and to apply it on one of your rendered elements, as explained in styled-components docs:

The styled method works perfectly on all of your own or any third-party component, as long as they attach the passed className prop to a DOM element.

  1. To style nested components, the className of the parent element must be applied on a parent DOM element as well; that is why JohnLi's answer has to add an extra <div className={className}> around the <Wrapper>.

But in your case, you could just style MyComponent and apply the className on the <Wrapper>:

export function MyComponent({
  className
}: {
  className?: string;
}): React.ReactElement {
  return (
    // Apply className directly on the Wrapper
    <Wrapper className={className}>
      This text can be re-colored
      <Text>hello there can be re-colored if styling nested Text</Text>
      <AnotherText>bye bye</AnotherText>
    </Wrapper>
  );
}

const NewlyStyledMyComponent = styled(MyComponent)`
  /* Directly style MyComponent */
  color: brown;
  background: magenta;

  /* Styling of nested components */
  ${Text} {
    color: white;
  }
`;

Demo: https://codesandbox.io/s/vibrant-worker-05xmil?file=/src/App.tsx

ghybs
  • 47,565
  • 6
  • 74
  • 99