Stop styled-components from leaking transient props into the DOM
Use ThemeProvider for design tokens and shouldForwardProp to keep transient props out of rendered HTML.
26 Jun 2026, 14:30 UTC

Transient props do not belong in the DOM
You create a styled.button that accepts $variant and $size to choose a theme-driven look. By default, styled-components forwards unknown props to the underlying element, so the rendered HTML can contain variant="primary" or size="large". Browsers usually ignore invalid attributes, but the DOM is noisier than it needs to be and React may warn about unrecognized attributes.
Share design tokens through ThemeProvider
ThemeProvider puts a theme object into React context. Inside a styled component, useTheme reads that object so colors, spacing, and breakpoints live in one place instead of being hardcoded.
import { createGlobalStyle, ThemeProvider, styled, useTheme } from 'styled-components';
const theme = {
colors: {
primary: '#2563eb',
primaryHover: '#1d4ed8',
surface: '#ffffff',
text: '#0f172a',
},
space: [0, 4, 8, 16, 24, 32],
};
export const GlobalStyles = createGlobalStyle`
html {
box-sizing: border-box;
}
body {
margin: 0;
font-family: system-ui, sans-serif;
color: ${({ theme }) => theme.colors.text};
background: ${({ theme }) => theme.colors.surface};
}
`;
export const Button = styled.button`
background: ${({ theme, $variant }) => {
if ($variant === 'primary') return theme.colors.primary;
return theme.colors.surface;
}};
color: ${({ theme, $variant }) => ($variant === 'primary' ? '#ffffff' : theme.colors.text)};
border: 1px solid ${({ theme }) => theme.colors.text};
border-radius: 6px;
padding: ${({ theme }) => theme.space[3]}px ${({ theme }) => theme.space[4]}px;
font-size: 16px;
cursor: pointer;
&:hover {
background: ${({ theme, $variant }) => ($variant === 'primary' ? theme.colors.primaryHover : theme.colors.surface)};
}
`;
export function App() {
return (
Save
);
}
Dollar-prefixed props such as $variant are the styled-components convention for transient values that affect styling but should not reach the DOM. However, the convention alone does not stop the prop from being forwarded; you still need shouldForwardProp.
Filter props before they reach the DOM
shouldForwardProp is a static method on a styled component. Return false for any prop you want to keep out of the rendered HTML.
import { styled } from 'styled-components';
const safeButton = styled.button.withConfig({
shouldForwardProp: (prop) => !prop.startsWith('$'),
})`
/* styles here */
`;
Apply it to the Button above so $variant and $size are used in interpolations but never appear as attributes on the <button> element.
Check your installed version before changing imports
styled-components v5 supports CommonJS and ESM. v6 is ESM-only and has stricter React 18 compatibility. Generated class names and CSS injection order can differ between major versions, so an upgrade is not purely cosmetic.
Run this in your project root to inspect the installed package:
npm ls styled-components
Expected: a tree entry showing the resolved version, such as styled-components@. You can also open node_modules/styled-components/package.json and check whether a module field exists; v6 emphasizes ESM entry points. No special permissions are required beyond read access to your project.
Risk: changing major versions can alter how styles are injected and may require updating server-side rendering setup. Pin the version in package.json until you have tested rendering in your target browsers.
Verify the result
- Render
ButtoninsideThemeProviderin your running app. - Open browser DevTools, inspect the
<button>element, and confirm novariant,size, or$variantattribute appears. - Confirm the computed background color matches the token from your theme.
If the attribute is still present, check that shouldForwardProp is attached to the styled component you are actually rendering, not a wrapper or base element.
Limitation
shouldForwardProp only filters props on the styled element it decorates. If you pass $variant through an intermediate component that forwards props manually, that component must also filter them. Avoid using dynamic interpolations for every static design decision; theme tokens are cheaper to audit and less work for the runtime.
Closing
Start by auditing your styled components for dollar-prefixed props. Add shouldForwardProp to components that accept them, centralize recurring values in a theme, and verify in DevTools that the DOM stays clean. Pin your styled-components major version and review the migration notes before moving from v5 to v6.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.