Chakra UI: extendTheme vs sx Prop for Component Styling
Decide when to customize Chakra UI globally with extendTheme and ThemeProvider versus locally with the sx prop.
07 May 2026, 13:34 UTC

Decision and constraints
You need to change how a Chakra UI component looks. The choice is between a global theme change that affects every matching component, and a local style override that affects one element. This decision matters because the wrong approach either scatters styling logic across your application or leaves your customizations silently unused.
Constraints:
- You are building or maintaining a React application with Chakra UI.
- You want reusable design-system decisions, such as button variants and color palettes, to stay consistent.
- You also need room for page-specific spacing or one-off layouts without breaking the design system.
Supported options compared
| Factor | extendTheme + ThemeProvider | sx prop |
|---|---|---|
| Scope | Entire component tree | Single element |
| Best for | Button variants, color palette, font scale, reusable component styles | Page-specific spacing, one-off layouts, temporary deviations |
| Maintenance | Centralized; one theme file updates many components | Scattered; each override must be edited individually |
| Theme integration | Merges custom tokens into the default Chakra theme | Applies Emotion-compatible styles directly, bypassing theme tokens |
| Failure mode | Silently falls back to default theme if ThemeProvider is missing | No global impact; only that element is styled differently |
Terms: extendTheme merges your custom colors, components, and fonts into Chakra's default theme. ThemeProvider makes that merged theme available through React context so every Chakra component in the tree can read it. The sx prop accepts style objects directly on a Chakra element, similar to inline styles but with theme-aware shortcuts.
Trade-offs
Global theme customization
Use extendTheme when the visual rule should apply everywhere. For example, if your primary buttons should always use a brand color and a specific border radius, defining that as a component variant means developers cannot accidentally create off-brand buttons. The downside is that you must wrap the application in ThemeProvider. If you forget, Chakra components render with the default theme and your custom variant is not applied, with no error message.
Local sx overrides
Use sx when the style belongs to one page or one component instance. For example, adding extra top margin to a section on the landing page does not deserve a global theme token. The downside is maintainability: if you later change your spacing scale, every sx override must be found and updated by hand.
Concrete implementation
Step 1: Confirm the Chakra UI major version
Chakra UI v1 and v2 use different theme structures. Run this in your project root:
npm list @chakra-ui/react
Where: terminal in the project root. Permissions: read access to package.json and node_modules. Expected check: the output shows @chakra-ui/react@2.x.x. Risk: theme code written for v2 will not work unchanged in v1.
Step 2: Create a custom theme
import { extendTheme } from '@chakra-ui/react';
const customTheme = extendTheme({
colors: {
brand: {
500: '#2563eb',
600: '#1d4ed8',
},
},
components: {
Button: {
variants: {
brand: {
bg: 'brand.500',
color: 'white',
_hover: { bg: 'brand.600' },
},
},
defaultProps: {
variant: 'brand',
},
},
},
});
export default customTheme;
This defines a brand color scale and makes every Button use the brand variant by default.
Step 3: Wrap the application
import { ThemeProvider } from '@chakra-ui/react';
import customTheme from './theme';
function App() {
return (
);
}
Where: your application entry point, typically App.jsx or main.jsx. Risk: omitting ThemeProvider causes all Chakra components to ignore customTheme and fall back to defaults.
Step 4: Use the themed component
import { Button } from '@chakra-ui/react';
export function SubmitButton() {
return Save changes;
}
Because defaultProps sets variant="brand", this button renders with your brand colors without setting variant on every instance.
Step 5: Apply a local override with sx
import { Box, Text } from '@chakra-ui/react';
export function HeroSection() {
return (
Welcome
);
}
This adds margin and padding only to this section. It does not change any global token.
Diagnostic: verify the result
- Open the running application in a browser.
- Open React DevTools and confirm
ThemeProviderappears in the component tree above your Chakra components. - Inspect a themed button in the browser's Elements panel. Its computed background should match your
brand.500value, not Chakra's default blue. - Temporarily remove
ThemeProviderfrom the component tree and refresh. If the button color reverts to the default, your theme was being applied correctly; restoreThemeProviderafterward.
Limitations
extendThemeandThemeProviderare Chakra UI v2 APIs. v1 uses a different theme shape and migration is not automatic.- Missing
ThemeProviderfails silently: components render with default styles and no console warning is guaranteed. - Heavy reliance on
sxscatters styling logic and makes global visual updates harder.
No rollback is required for this decision because it changes rendering behavior, not persistent state. If a custom theme causes problems, revert the theme file and remove ThemeProvider from the entry point.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.