styled-components: styles passed into styled(Component) don't overwrite base styles

Environment

npx envinfo --system --binaries --npmPackages styled-components,babel-plugin-styled-components --markdown --clipboard - zsh: command not found: npx

Reproduction

https://codesandbox.io/s/k51yyo4v35

Heading.js

import * as React from "react";
import styled, { css } from "styled-components";

const Wrapper = styled.h1`
  margin-top: 0;
  margin-bottom: 0;
`;

export const Heading = props => {
  const WrapperWithAnotherTag = props.tag && props.tag !== "h1"
      ? Wrapper.withComponent(props.tag) : Wrapper;

  return (
    <WrapperWithAnotherTag className={props.className}>
      {props.children}
    </WrapperWithAnotherTag>
  );
};

Index.js

import React from "react";
import ReactDOM from "react-dom";
import styled, { css } from "styled-components";

import { Heading } from "./heading";

const Name = styled(Heading)`
  margin-bottom: 10px;
`;

function App() {
  return (
    <div className="App">
      <Name>Here is a title with margin</Name>
      <Name tag={"h2"}>Here is a title without margin -_-</Name>
    </div>
  );
}

const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);

Expected Behavior

<Name tag={"h2"}>Here is a title without margin -_-</Name>

should have margin-bottom

Actual Behavior

<Name tag={"h2"}>Here is a title without margin -_-</Name>

Doesn’t have margin-bottom because it doesn’t overwrite base styles

P.S. it is simplified example!

About this issue

  • Original URL
  • State: closed
  • Created 6 years ago
  • Reactions: 17
  • Comments: 18 (3 by maintainers)

Most upvoted comments

Alright so the issue here is related to the order of composed classNames. If you inspect the H2, the CSS for margin-bottom: 10px is there but is being overridden by the base component styles due to how s-c is composing the passed class name vs the class name it injects itself.

@kitten @mxstbr do you guys remember why we put the SC classnames last instead of first?

Nvm it’s a specificity thing. Because all the classNames are at the same specificity level it falls back to stylesheet insertion order. You can boost the specificity of the override style with this trick:

const Name = styled(Heading)`
  && {
    margin-bottom: 10px;
  }
`;

I just ran into this and while I understand the cause and the solution, the solution feels like a workaround for unexpected behavior. I would expect that styles for an extended component always follow the styles of the base component – that’s the whole point of extending.

This seems to work as expected in v3. After I updated to v4 styles doesn’t applies in right order. This should be reopen.

What is the current state of this issue?

I agree with @stonebk . This should be default behaviour and this issue should be reopened. @probablyup Why was the decision made to prioritise base styles over extended ones?

Not working, even with

&& {
    ............
}

Is this “resolved” means to be in v5? Problem still occurs on 4.3.2. Thanks!

The solution that worked for me was to pass the className prop into the styled component you wish to override. Thanks StackOverflow!

The solution that worked for me was to pass the className prop into the styled component you wish to override. Thanks StackOverflow!

That’s a different issue. The above issue is understanding that you can pass a className into the component, the issue arises when we have multiple levels of class names of the same specificity.

Example follows:

const ComponentA = styled.div`
  width: 100%;
  height: 100%;
`

function ExtendedComponent({ className }) {
  return <ComponentA className={className} />
}

const StyledExtendedComponent = styled(ExtendedComponent)`
  width: 50%;
`

width: 50% will not be applied in this case. width: 100% will be applied.

To fix the issue we currently have to use:

const StyledExtendedComponent = styled(ExtendedComponent)`
  && {
    width: 50%;
  }
`

This really seems like a bug rather than a feature

Still happening and does not fixed in 4.2.1 Why issue is closed?

Still happening here with no third party components framework.