styled-components v7 drops vendor prefixes by default and hides the plugin types
Fast, expressive styling for React. Server components, client components, streaming SSR, React Native—one API.
At a glance
- What is it?
- styled-components is a runtime CSS-in-JS library for React that ships its own TypeScript types and needs no build step from consumers. Its v7 line changes two things a v6 codebase will trip over: the enableVendorPrefixes prop is gone in favour of an opt-in plugin, and that plugin's types are only exported from a subpath.
- Who is it for?
- Adopt styled-components if your team writes React in TypeScript, wants media queries, nesting and keyframes without a build step, and needs SSR and React Native from one API. Do not adopt it if your browser matrix is older than React's own floor and you rely on vendor prefixes, since the bundled prefix set stops at Chrome 45 and Safari 9, or if you need a stable major to pin, because the newest releases on the feed are 7.0.0 and 6.6.0 prereleases.
- Can I use it commercially?
- Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Yes. The repository last received commits 2 days ago.
- What is it written in?
- Mainly TypeScript, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on September 30, 2026, and from our analysis. They are not legal advice.
Editorial analysis
npm install gets the published package, not this tree
Three package managers, one dependency:
npm install styled-componentspnpm add styled-componentsyarn add styled-componentsThere is no build plugin to configure, and the types ship inside the package, so there is no `@types` install and no manual generic plumbing. What you get from a clone is something else: the root manifest is named `styled-components-project` and is marked `"private": true`, so the checkout is a pnpm workspace where `pnpm --filter styled-components build` is the build script, `packageManager` is `[email protected]` and the root declares `node >= 14`.
That is the whole difference between reading the source and using the library. The tree carries `babel.config.cjs` and `babel-preset.cjs` because the library itself is compiled, while the person consuming it compiles nothing. Consumers should read `src/` and the published package as two different artifacts.
Every recent release is a prerelease, on two version lines at once
The three newest releases on the feed are all prereleases, and they are not on one line. There is `[email protected]` from 2026-09-08, then on 2026-09-25 both `[email protected]` and `[email protected]`.
So the 6.x line and the 7.x line are both publishing prereleases on the same day, and no stable 7.0 exists in that list. What `npm install styled-components` resolves to depends on which dist-tag `latest` points at, and neither the README nor the release names say. For a team that needs a reproducible install, that is the gap to close by pinning an exact version rather than a range.
The release process itself is ordinary changesets, with a `.changeset/` directory at the root and `changeset publish` in the release script. The last push was on 2026-09-28, so the branch is moving; the question is only which artifact a plain install hands you.
Prefixes are off by default, and the opt-in has a browser floor
CSS comes out unprefixed. Turning prefixes on is a deliberate step, and the mechanism is a plugin attached to a subtree:
import { StyleSheetManager } from 'styled-components';
import { prefixPlugin } from 'styled-components/plugins';
<StyleSheetManager plugins={[prefixPlugin]}>
<App />
</StyleSheetManager>;Note what is gone in v7: the `enableVendorPrefixes` prop from v6 has been removed rather than deprecated. A v6 codebase that set it has to move to the plugin, and the behaviour changes from a global switch to a wrapper you place where you want it.
The floor is the part that bites. The included prefix set targets Chrome 45, Firefox 36, Safari and iOS 9, and Edge 12, which the documentation ties to the browser floor for the JavaScript APIs React itself requires. If your support matrix is older than React's, this plugin will not cover it. For anything else you declare both the prefixed and the standard form yourself, or extend the plugin, and both paths mean owning the output.
The plugin types are not on the package root
Writing a custom plugin means importing from a subpath. `SCPlugin`, `DeclResult`, `DeclTransform` and `SelectorTransform` are exported only from `styled-components/plugins` and not from the package root. An import written against the root path fails at build time, and the error will not tell you the subpath exists.
The contract is small and the ordering rule is the part to get right. Plugins apply left to right, and a later plugin's `decl` runs on every declaration an earlier plugin emitted, which is why returning `undefined` on the miss path is what keeps a custom plugin cheap. Two habits keep a chain safe: skip properties that already start with `-`, which is what `prefixPlugin` does, and note that plugins can compose in either order without double-prefixing.
That last property is a real convenience and it is not free. A chain of transforms where one of them forgets the `-` check will happily emit `-webkit--webkit-transform` on the next pass, and nothing in the API will warn you.
Transient props need a dollar sign, and the generic has to match
Props reach the stylesheet through interpolation functions, and any prop you do not want on the DOM has to be prefixed with `$`:
import styled from 'styled-components';
const Button = styled.button<{ $primary?: boolean }>`
background: ${props => (props.$primary ? 'palevioletred' : 'white')};
color: ${props => (props.$primary ? 'white' : 'palevioletred')};
font-size: 1em;
padding: 0.25em 1em;
border: 2px solid palevioletred;
border-radius: 3px;
`;The `$` is what keeps the value out of the rendered markup, and it appears twice: in the TypeScript generic and in the interpolation. Rename `primary` to `$primary` and you are making a breaking change at every call site, in both places, which is why the convention is worth adopting on day one rather than retrofitting.
The `as` prop is the other half. `<Button as="a" href="/home">` renders an anchor with Button's styles, which is convenient until you remember that any selector you wrote assuming a button no longer matches a link.
createTheme tokens are strings, and arithmetic on them is dropped
`createTheme` exists for server components. It returns a `theme` and a `GlobalStyle` component, the latter named `ThemeVars` in the example, which you render at the root to emit the CSS custom property declarations while still passing the theme to `ThemeProvider` for stable hashes. The payoff is that class name hashes stay the same across theme variants, so switching between light and dark does not produce a hydration mismatch.
The trap is in the interpolation. A token is a placeholder reference, not a raw value, so this is fine:
// works
padding: ${theme.space.md};
margin: ${theme.space.sm} ${theme.space.md};
top: calc(${insets.top}px + ${theme.space.md});Doing the same addition in JavaScript instead of in `calc()` produces a malformed string that the browser drops, and the rule you land on is to use `calc()` for composition or reach for `theme.raw.space.md` when you genuinely need the underlying number. The variable name is mechanical too, `theme.colors.fg` resolving to `var(--sc-colors-fg, palevioletred)`, so a token you invent gets a predictable name you can also target from plain CSS.
One maintainer, and no stability promise behind the major
The README states that styled-components is largely maintained by one person, and asks for funding through Open Collective for consistent long-term support. The package manifest names Glen Maddern as author. That is the honest version of the bus factor, and it belongs in your decision, because a major version bump is one person's judgement call rather than a review process.
The tree backs that up. `.husky/` and `lint-staged` gate commits, Biome at 2.5.7 formats and lints, knip finds unused exports, and there are dedicated scripts for release notes, prerelease notes, an effect gate and `node scripts/verify.mjs`. It is a disciplined repository with a narrow set of maintainers.
Two root files are unusual: `AGENTS.md` and `CLAUDE.md`, alongside `CORE_TEAM.md` and `CHANGELOG.md`. A library shipping instructions addressed to coding agents says something about where its contributors are expected to come from, and it is worth reading `AGENTS.md` before you contribute a change.
Runtime generation, utility markup, and the other tagged-template library
The comparison worth making is architectural, not about which output looks nicer. styled-components generates CSS at runtime through template literals, so nesting, media queries, pseudo-selectors, keyframes and global styles all work without a build step, and the same API is stated to work across server components, client components, streaming SSR and React Native with automatic runtime detection. Its cost is a runtime dependency, and the README puts the gzipped size under 13kB.
Tailwind takes the opposite route: utility class names in your markup and a build step that produces the stylesheet, so there is no runtime style generation and nothing to ship. You get full CSS either way, but the authoring surface is class names in JSX rather than a stylesheet next to the component.
Emotion is the closer comparison, since it also uses tagged templates and a runtime model. The difference in approach here is in the surface rather than the philosophy: styled-components is built around a default export with a `.plugins` subpath for the plugin contract, and the vendor prefix decision is a v7 plugin rather than a prop. If you are choosing between the two, the deciding questions are the TypeScript story and whether your prefix needs are older than React's browser floor, not the syntax.
Editorial conclusion
Adopt styled-components if your team writes React in TypeScript, wants media queries, nesting and keyframes without a build step, and needs SSR and React Native from one API. Do not adopt it if your browser matrix is older than React's own floor and you rely on vendor prefixes, since the bundled prefix set stops at Chrome 45 and Safari 9, or if you need a stable major to pin, because the newest releases on the feed are 7.0.0 and 6.6.0 prereleases. Verify three things before you pin: which version `npm install styled-components` actually resolves, whether your existing `enableVendorPrefixes` usage has a v7 equivalent in mind, and whether any import of SCPlugin or DeclResult from the package root needs moving to styled-components/plugins.
Frequently asked questions
What is a styled component?
A styled component is a React component created by tagging a template literal, so that `styled.button` returns a component whose CSS lives in the template rather than in a separate file or a class name you write yourself. Scoping is automatic, and styles are delivered only when needed with no build step required.
Is styled-component deprecated?
The repository is not archived and the last push was on 2026-09-28, but the three newest releases are prereleases, including 7.0.0 prereleases and a 6.6.0 prerelease. In v7 the `enableVendorPrefixes` prop from v6 has been removed in favour of the opt-in `prefixPlugin`, so parts of the v6 API are gone while the library itself is not deprecated.
how to install styled components
Run `npm install styled-components`, or `pnpm add styled-components` or `yarn add styled-components`. There is no build plugin to register and no separate types package, because the built-in types ship with the package. If you need reproducibility, pin an exact version, since the release feed currently carries 7.0.0 and 6.6.0 prereleases on two lines.
how to use props in styled components
Interpolate a function that receives props, and prefix any prop you do not want forwarded to the DOM with `$`. The example types the component as `styled.button<{ $primary?: boolean }>` and reads `props.$primary` inside the template, so the dollar sign appears in both the generic and the interpolation.
how to use css variables in styled components
Use `createTheme`, which turns your tokens into CSS custom properties and returns a `theme` plus a `GlobalStyle` component to render at the root. Class name hashes stay stable across theme variants, so switching light and dark does not cause a hydration mismatch. Tokens are placeholder references, so compose them with `calc()` rather than JavaScript arithmetic.
Is styled component CSS in JS?
It emits real CSS at runtime, described as full CSS with no compromises, supporting media queries, pseudo-selectors, nesting, keyframes and global styles. The difference from a build-time approach is that nothing needs a build step, and the CSS arrives in the page rather than in a separate file you compile.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/styled-components-styled-components)