What do I need to do to migrate to v6?

First, let's start by updating the necessary packages to their latest versions.

If you're using NPM:

npm install styled-components@^6.0.0 stylis@^4.0.0
npm uninstall @types/styled-components

If you're using Yarn:

yarn add styled-components@^6.0.0 stylis@^4.0.0
yarn remove @types/styled-components

As styled-components now provides its own types, there's no longer a need for community ones.

TypeScript

Good news for TypeScript enthusiasts – styled-components is now natively written in TypeScript! Even if you haven't used TypeScript before, it's recommended for improving the reliability of your project as it can alert you when you're using an unknown prop or if a prop has a different value than expected.

However, if you don't use TypeScript in your project, don't worry! IDEs like VS Code will still pick up the types and provide hints as you write your code.

shouldForwardProp is no longer provided by default

If haven't migrated your styling to use transient props ($prefix), you might notice React warnings about styling props getting through to the DOM in v6. To restore the v5 behavior, use StyleSheetManager:

import isPropValid from '@emotion/is-prop-valid';
import { StyleSheetManager } from 'styled-components';


function MyApp() {
    return (
        <StyleSheetManager shouldForwardProp={shouldForwardProp}>
            {/* other providers or your application's JSX */}
        </StyleSheetManager>
    )
}


// This implements the default behavior from styled-components v5
function shouldForwardProp(propName, target) {
    if (typeof target === "string") {
        // For HTML elements, forward the prop if it is a valid HTML attribute
        return isPropValid(propName);
    }
    // For other elements, forward all props
    return true;
}

Vendor prefixes are omitted by default

As the web and browsers have matured significantly by 2023, vendor prefixing is often unnecessary. Therefore, for the v6 release, we've decided to omit automatic prefixing by default to reduce the amount of CSS delivered to a page. If you prefer the v5 behavior, you can restore it via StyleSheetManager:

import { StyleSheetManager } from 'styled-components';


function MyApp() {
    return (
        <StyleSheetManager enableVendorPrefixes>
            {/* other providers or your application's JSX */}
        </StyleSheetManager>
    )
}

To accommodate this change, the original disableVendorPrefixes prop was inverted to enableVendorPrefixes; if you have disableVendorPrefixes set, you can now remove it as it's the new default.

Update stylis plugins

styled-components v6 uses the newer stylis v4; if you are providing stylisPlugins to StyleSheetManager, ensure the plugins are up-to-date. For instance, stylis-plugin-rtl released a new version to support the updated stylis.

Nested syntax handling

With the stylis v4 upgrade came a change to how nested selectors are handled which now correctly mirrors browser behavior. Specifically, pseudoselectors (e.g. :before) that do not start with & will not have the ampersand implicitly added anymore.

v5 behavior

styled.div`
  :hover { color: red; }
`
// .[classname]:hover { color: red; }


styled.div`
  &:hover { color: red; }
`
// .[classname]:hover { color: red; }

v6 behavior

styled.div`
  :hover { color: red; }
`
// .[classname] :hover { color: red; } (equivalent to .[classname] *:hover)


styled.div`
  &:hover { color: red; }
`
// .[classname]:hover { color: red; }

Transient $as and $forwardedAs props have been dropped

To reduce confusion around application order, we've dropped the transient $as and $forwardedAs props. Please use the regular as and forwardedAs props instead.

Dropped legacy withComponent() API

This change has been a long time coming. The withComponent API is no longer supported, so please use the as prop instead. You can specify as at definition time via attrs or at runtime:

import styled from 'styled-components';


const Button = styled.button`
    background: blue;
    color: white;
`;


const ButtonLink = styled(Button).attrs({ as: 'a' })``;


// These are equivalent, but `ButtonLink` allows for attaching further styling if desired.
<Button as="a" href="https://styled-components.com">
<ButtonLink href="https://styled-components.com">

Minimum Node support raised to v16+

In line with the maintenance schedule for Node, we now support v16 as the oldest runtime that's still receiving security patches.

What do I need to do to migrate to v5?

Ready for this?

npm install styled-components@^5.0.0 react@^16.8 react-dom@^16.8 react-is@^16.8

If you're using React Native, you'll need at least v0.59 (the first version to support hooks.)

That's it. 💥


styled-components v5 does not introduce any breaking public API changes, and adds the following:

  • Total rewrite of the core stylesheet engine, tuned for performance

  • New hooks-based component model

  • StyleSheetManager has new props:

    • disableCSSOMInjection
    • disableVendorPrefixes
    • stylisPlugins
Note

Note: The subfunction object-form .attrs({ prop: props => {} }) syntax that was deprecated in v4 is removed in v5. Use function-form attrs instead .attrs(props => ({})) (you should have been seeing console warnings to make this update ahead of time.)

Check out the official announcement post for more information and to learn about what went into v5!

For jest users

Update to jest-styled-components v7:

npm install jest-styled-components@^7.0.0

Note regarding css @import and createGlobalStyle

At this time we do not recommend using @import within cGS due to some issues with how browsers process @import via the CSSOM APIs. Instead it's best to place these in your core index.html file (generated or static) within a typical <style> tag.

What do I need to do to migrate to v4?

This is a pretty big release with lots of changes both under the hood and at the API level. As the beta progresses, we will try to release codemods to make the items below simpler. Also, if you find any issues with the steps below, please leave constructive feedback!

  1. Upgrade to the latest styled-components:
npm install styled-components@^4.0.0
  1. Make sure your application is using react >= 16.3; internally we are using the new React.forwardRef API and new context APIs if you wish to try and polyfill for older React version support
npm install react@^16.3 react-dom@^16.3
Note

If you are using enzyme or other dependencies like react-test-renderer, there may be more related upgrades to complete if you are coming from an old version of react.

  1. If you are using the .extend API, switch your components to use styled(StyledComponent) instead.

A codemod is available to expedite this.

🚫

import styled from 'styled-components'


const Component = styled.div`
  background: blue;
  color: red;
`


const ExtendedComponent = Component.extend`
  color: green;
`

import styled from 'styled-components'


const Component = styled.div`
  background: blue;
  color: red;
`


const ExtendedComponent = styled(Component)`
  color: green;
`

See the "extending styles" documentation for more examples.

  1. If you were using the injectGlobal API to add global styles to your page, use the new createGlobalStyle helper component instead.

A codemod is available to expedite this.

🚫

import { injectGlobal } from 'styled-components'


injectGlobal`
  body {
    color: red;
  }
`

import { createGlobalStyle } from "styled-components"


const GlobalStyle = createGlobalStyle`
  body {
    color: red;
  }
`


// later in your app's render method
<React.Fragment>
  <Navigation />
  <OtherImportantTopLevelComponentStuff />
  <GlobalStyle />
</React.Fragment>

See the documentation for createGlobalStyle to see all the cool stuff you can do with it that wasn't possible before with injectGlobal!

  1. If you were using the innerRef prop, change it to a normal ref.

🚫

const Component = styled.div`
  background: blue;
  color: red;
`


// later in your render method
<Component innerRef={element => { this.myElement = element }}>Something something</Component>

const Component = styled.div`
  background: blue;
  color: red;
`


// later in your render method
<Component ref={element => { this.myElement = element }}>Something something</Component>
  1. If you're using the keyframes component in a partial without the css helper, you'll need to use the helper now. In general, always use the css helper when composing styling partials to be interpolated into a styled component.

🚫

import styled, { keyframes } from 'styled-components'


const animation = keyframes`
  0% {
    opacity: 0;
  }


  100 {
    opacity: 1;
  }
`


const animationRule = `
  ${animation} 1s infinite alternate
`


const Component = styled.div`
  animation: ${animationRule};
`

import styled, { css, keyframes } from 'styled-components'


const animation = keyframes`
  0% {
    opacity: 0;
  }


  100 {
    opacity: 1;
  }
`


const animationRule = css`
  ${animation} 1s infinite alternate;
`


const Component = styled.div`
  animation: ${animationRule};
`
  1. If you're using attrs({}) and some of the attributes you pass to it is a Function, it's recommended to switch to the new attrs(props => ({})) syntax instead for easier and more powerful composition.

🚫

import styled from 'styled-components'


const Input = styled.input.attrs({
  type: props => props.inputType,
})`
  background: blue;
  color: red;
`

import styled from 'styled-components'


const Input = styled.input.attrs(props => ({
  type: props.inputType,
}))`
  background: blue;
  color: red;
`
  1. If you're using TypeScript, the typings are now located in DefinitelyTyped:
npm install @types/styled-components

That's it! Aside from migrating, we also highly recommend reading up on the new "as" prop which is intended to replace the withComponent API in the future.

Can I nest rules?

Yes: nesting is a feature intentionally ported from Sass. Used sparingly it's a great way to lighten your code by reducing the need to create explicit classes for every element.

It can also be used by parent components to define contextual constraints that aren't properly a concern of the affected children:

First
Second
Third
First
Second
Third

It's also incredibly convenient to co-locate media queries, since we can see at a glance exactly how the component will respond at any resolution.

Hello world!

Can I use CSS frameworks?

Integrating an existing CSS framework with styled-components is really easy! You can use its existing class names alongside your components.

For example, imagine you have an existing app with two classes you want to use again: .small and .big. If you want the class to always be attached to the component, you should use the attrs method to attach it. If you want to attach it only in some cases you can use the className props like you always have!

If the framework has a bunch of raw global CSS that needs to be included on the page, you can add it using the createGlobalStyle API. This is also useful for things like CSS resets.

Note

Note that for styled-components v3 and below, the previous API for global styles was injectGlobal.

How can I override styles with higher specificity?

The way to override styles with a high specificity is to simply increase the specificity of your own styles. This could be done using !important, but that's error prone and generally not a good idea.

We recommend the following technique:

const MyStyledComponent = styled(AlreadyStyledComponent)`
  &&& {
    color: #BF4F74;
    font-weight: bold;
  }
`

Each & gets replaced with the generated class, so the injected CSS then looks like this:

.MyStyledComponent-asdf123.MyStyledComponent-asdf123.MyStyledComponent-asdf123 {
  color: #BF4F74;
  font-weight: bold;
}

The repeated class bumps the specificity high enough to override the source order without being very tedious to write!

How can I override inline styles?

Inline styles will always take precedence over external CSS, so you cannot override it by simply increasing specificity.

There is a neat trick however, which is to use the style element-attr CSS Selector in conjunction with !important:

const MyStyledComponent = styled(InlineStyledComponent)`
  &[style] {
    font-size: 12px !important;
    color: blue !important;
  }
`

Why do my DOM nodes have two classes?

Each node actually has two classes connected to it: one is static per component, meaning each element of a styled component has this class. It hasn't any style attached to it. Instead, it's used to quickly identify which styled component a DOM objects belongs to or to make minor changes in the DevTools. It's also used for component selectors. The static class probably will look something like: .sc-fVOeaW.

The other is dynamic, meaning it will be different for every element of your styled component with different props, based on what the interpolations result in. It will probably look like .fVOeaW (note the lack of "sc" prefix.)

For example, the styled component <Button /> would render with the same static class every time. If the styles are changed using interpolations, like <Button secondary />, then the dynamic class will be a different one, while the static class would remain the same.

When to use attrs?

You can pass in attributes to styled components using attrs, but it is not always sensible to do so.

The rule of thumb is to use attrs when you want every instance of a styled component to have that prop, and pass props directly when every instance needs a different one:

const PasswordInput = styled.input.attrs(props => ({
  // Every <PasswordInput /> should be type="password"
  type: "password"
}))``


// This specific one is hidden, so let's set aria-hidden
<PasswordInput aria-hidden="true" />

The same goes for props that can be inferred based on the "mode" of another prop. In this case you can set a property on attrs to a function that computes that prop based on other props.

I am a library author. Should I bundle styled-components with my library?

If you are a library author, we recommend that you should not bundle and ship styled-components module with your library. There are two steps that you need to do to achieve this:

  • Marking styled-components as external in your package dependencies
  • Removing styled-components from your library bundle

Marking styled-components as external in your package dependencies

To do this, you will need to move it from dependencies to devDependencies and include it in the peerDependencies list in your package.json file:

{
-   "dependencies" : {
+   "devDependencies" : {
      "styled-components": "^3.4.9"
    },
+   "peerDependencies" : {
+     "styled-components": ">= 3"
+   }
  }

Moving styled-components to devDependencies will guarantee that it wouldn't be installed along with your library (npm install or yarn add will ignore devDependencies when a library is installed).

Adding styled-components to peerDependencies will signal your library consumers that styled-components is not included with the library and they need to install it themselves.

Also, note that in the peerDependencies section the version string has been made a more permissive >= 3. This allows future versions of styled-components to work automatically and you can simply narrow the range with a patch update to your library if a breaking change is eventually added.

Removing styled-components from your library bundle

If you are bundling your library before shipping it, make sure that you are not bundling styled-components along with it. Here are some examples of how to do this with some popular module bundling tools:

With Microbundle

If you are using Microbundle, it will handle this step automatically. Microbundle treats every dependency in the peerDependencies list as external and excludes it from the build for you.

With Rollup.js

If you are using Rollup.js, you should provide an external option in your config:

export default {
    entry: "my-awesome-library.js",
+   external: [
+     "styled-components"
+   ]
  }

Another approach is to use the rollup-plugin-peer-deps-external plugin which will automatically add the peerDependencies in the external option array for you.

+ import peerDepsExternal from 'rollup-plugin-peer-deps-external';

  export default {
    entry: "my-awesome-library.js",
+   plugins: [
+    // Preferably set as first plugin.
+    peerDepsExternal(),
+   ]
  }

With Webpack

If you are using Webpack, you should provide an externals option in your config:

modules.export = {
    entry: "my-awesome-library.js",
+   externals: {
+     "styled-components": {
+       commonjs: "styled-components",
+       commonjs2: "styled-components",
+       amd: "styled-components",
+     },
+   },
  }
Note

You can find more useful information on how to bundle a library with Webpack at "Authoring Libraries" section of Webpack documentation.

Why am I getting a warning about several instances of module on the page?

If you are seeing a warning message in the console like the one below, you probably have several instances of styled-components initialized on the page.

It looks like there are several instances of "styled-components" initialized in this application. This may cause dynamic styles not rendering properly, errors happening during rehydration process and makes you application bigger without a good reason.


If you are using a building tool like webpack, consider checking your bundle for duplication of the "styled-components" module.

This may cause dynamic styles not working properly or even errors during rehydration if you are using server-side rendering.

Possible reasons

There are several common reasons for this to happen:

  • You have several applications that are using styled-components running on the same page (e.g., several entry points in webpack are loaded on the same page)
  • You have another styled-components library somewhere in your dependencies
  • You have a monorepo structure for your project (e.g, lerna, yarn workspaces) and styled-components module is a dependency in more than one package (this one is more or less the same as the previous one)

Running multiple applications on one page

If you have several applications running on one page, consider using one styled-components module for all of them. If you are using webpack, you can use CommonsChunkPlugin to create an explicit vendor chunk, that will contain the styled-components module:

module.exports = {
    entry: {
+     vendor: ["styled-components"],
      app1: "./src/app.1.js",
      app2: "./src/app.2.js",
    },
    plugins: [
+     new webpack.optimize.CommonsChunkPlugin({
+       name: "vendor",
+       minChunks: Infinity,
+     }),
    ]
  }

Duplicated module in node_modules

If you think that the issue is in duplicated styled-components module somewhere in your dependencies, there are several ways to check this. You can use npm ls styled-components, yarn list --pattern styled-components or find -L ./node_modules | grep /styled-components/package.json commands in your application folder.

If none of these commands identified the duplication, try analyzing your bundle for multiple instances of styled-components. You can just check your bundle source, or use a tool like source-map-explorer or webpack-bundle-analyzer.

If you identified that duplication is the issue that you are encountering there are several things you can try to solve it:

If you are using npm you can try running npm dedupe. This command searches the local dependencies and tries to simplify the structure by moving common dependencies further up the tree.

Note

Be aware that npm dedupe doesn't work well with symlinked folders (i.e., when you use npm link)

If you are using webpack, you can change the way it will resolve the styled-components module. You can overwrite the default order in which webpack will look for your dependencies and make your application node_modules more prioritized than default node module resolution order:

resolve: {
+   alias: {
+     "styled-components": path.resolve(appFolder, "node_modules", "styled-components"),
+   }
  }

Usage with Lerna

One possible fix to get styled-components to run in a Lerna monorepo across packages, is to hoist shared dependencies to the root of your monorepo file. Try running the bootstrap option with the --hoist flag.

lerna bootstrap --hoist

Alternatively, you can remove styled-components from your package.json file and hoist it manually to your top-level package.json file.

Example of a package.json file in a Lerna root folder

{
  "name": "my-styled-monorepo",
  "devDependencies": {
    "lerna": "3.6.0"
  },
  "dependencies": {
    "styled-components": "3.4.5"
  },
  "scripts": {
    "bootstrap": "lerna bootstrap",
    "clean": "lerna clean",
    "start": "lerna run start",
    "build": "lerna run build"
  }
}

Why should I avoid declaring styled components in the render method?

By declaring a styled component inside the render method of a react component, you are dynamically creating a new component on every render. This means that React will have to discard and re-calculate that part of the DOM subtree on each subsequent render, instead of just calculating the difference of what changed between them. This leads to performance bottlenecks and unpredictable behavior.

🚫

const Header = () => {
  const Title = styled.h1`
    font-size: 10px;
  `


  return (
    <div>
      <Title />
    </div>
  )
}

const Title = styled.h1`
  font-size: 10px;
`


const Header = () => {
  return (
    <div>
      <Title />
    </div>
  )
}

Why am I getting HTML attribute warnings?

The warning message below indicates that non-standard attributes are being attached to HTML DOM elements such as <div> or <a>. If you are seeing this warning message, it is likely that you or a library you are using is attaching props as attributes to HTML DOM elements.

Warning: Received "true" for a non-boolean attribute

If you're seeing this warning you are probably passing true where "true" would be appropriate. It's likely that this comes from a .attrs property, or from a completely unrelated prop that you're passing to a styled(Component) component.

To learn more about how props are passed, see this section.

For example:

const Link = props => (
  <a {...props} className={props.className}>
    {props.text}
  </a>
)


const StyledComp = styled(Link)`
  color: ${props => (props.red ? 'red' : 'blue')};
`


<StyledComp text="Click" href="https://www.styled-components.com/" red />

This will render:

<a text="Click" href="https://www.styled-components.com/" red="true" class="[generated class]">Click</a>

React will warn on non-standard attributes being attached such as "red" and "text", which are not valid HTML attributes for the <a> element.

To fix this, you can use transient props or destructure props:

transient props (since 5.1)

You can use transient props to fix this:

const Link = ({ className, text, ...props }) => (
  <a {...props} className={className}>
    {text}
  </a>
)


const StyledComp = styled(Link)`
  color: ${props => (props.$red ? 'red' : 'blue')};
`


<StyledComp text="Click" href="https://www.styled-components.com/" $red />

destructure props

If you use a version < 5.1 or if you can't use transient props, you can use argument destructuring to pull out those known styling props:

const Link = ({ className, red, text, ...props }) => (
  <a {...props} className={className}>
    {text}
  </a>
)


const StyledComp = styled(Link)`
  color: ${props => (props.red ? 'red' : 'blue')};
`


<StyledComp text="Click" href="https://www.styled-components.com/" red />

This will render:

<a href="https://www.styled-components.com/" class="[generated class]">Click</a>

When you use argument destructuring, any variables pulled out of the props object will not be included when spread-applying the remaining props (...props);

Which browsers are supported?

styled-components supports the same set of browsers as the current React version.

  • v2.x (React v0.14+): IE9+, all evergreen browsers
  • v3.x (React v0.14+): IE9+, all evergreen browsers
  • v4.x (React v16.3+): IE11, IE 9+ (with Map + Set polyfills), all evergreen browsers
  • v5.x (React v16.3+): IE11, all evergreen browsers

Evergreen browsers include Chrome and Firefox (and derivatives) as they can be updated regardless of operating system version. Edge and Safari should both also work fine since all versions for the last several years support the relevant APIs.

How do I use styled-components with create-react-app?

The basic functionality of the library should work out of the box like any other library.

However, if you want to do server-side rendering or take advantage of some of the advanced capabilities of the styled-components babel plugin without ejecting you'll need to set up react-app-rewired and react-app-rewire-styled-components.

How can I fix issues when using npm link or yarn link?

Local linking can be a useful tool to co-develop projects simultaneously. However, it creates chaotic situations with libraries that are meant to be used as singletons like react and styled-components since each of your local projects likely has a full set of development dependencies downloaded (and bundlers prefer local versions of dependencies by default.)

The solution is to add aliasing. Here's an example config for webpack:

// const path = require('path');


{
  resolve: {
    alias: {
      // adjust this path as needed depending on where your webpack config is
      'styled-components': path.resolve('../node_modules/styled-components')
    }
  }
}

This ensures that for your build the same copy of the library will always be used, even across symlinked projects.

Linking in an SSR SCENARIO.

If you are using the collectStyles function on a project with linked components you will end up in a complex scenario. Basically what's happening is that because of v4 new static context API different styled-component modules are now managing their own list of styled-components to render, from the host app it appears as though there's nothing to extract because no styled components have been created in that scope they were created from the linked package scope.

How do I solve it?

One solution is to add an alias to the styled-components module path resolution to always point to the 'host' application. Hopefully there are a bunch of libraries to do that we will use for this example module-alias. At the very top of your SSR index file add:

const path = require('path');
const moduleAlias = require('module-alias');


moduleAlias.addAlias('styled-components', path.join(__dirname, '../node_modules/styled-components'));

This will tell node to resolve all import/require's of styled-components to __dirname, '../node_modules/styled-components'

How do I fix flickering text after server side rendering?

When using global styling APIs like createGlobalStyle or the former injectGlobal, adding and removing certain styles from the DOM like @font-face definitions can cause momentary flickering of text on the page. This typically happens during the rehydration phase of server-side rendering. We're still tweaking how these behaviors work to avoid the issue long-term.

However, there is a CSS solution to the problem in the font-display CSS rule. By setting the rule to "fallback" mode, once a font has been loaded it will not be reloaded. This eliminates the flicker.

@font-face {
  font-family: 'Foo';
  src: url('/path/to/foo.woff') format('woff');
  font-style: normal;
  font-weight: 400;
  font-display: fallback; /* <- this can be added to each @font-face definition */
}

Missing Declarations for styled-components/native?

If you're getting the error message:

Could not find a declaration file for module 'styled-components/native'

In a React Native project using TypeScript, it is because you need to add @types/styled-components-react-native.