Deciding When to Centralize Chakra UI Tokens with extendTheme
Use Chakra UI extendTheme for global design tokens, and component style props for one-off styling. Includes a comparison table and validation steps.
01 May 2026, 01:42 UTC

The decision: centralize tokens or style per component
You are building a React application with Chakra UI, and the design system specifies brand colors, a custom type scale, and breakpoints that differ from Chakra's defaults. A common temptation is to pass values such as color="brand.500" or fontSize="xl" directly on every component. That works for a few elements, but it duplicates tokens across the codebase and makes a future brand change a find-and-replace across many files.
The useful takeaway: use extendTheme to define tokens once when they appear in multiple components. Use component-level style props only for one-off deviations.
Constraints and assumptions
- Chakra UI v2 with React 18 or later.
- You want a single source of truth for colors, fonts, and breakpoints.
- You do not want to eject from Chakra UI or maintain a fork of the library.
extendTheme is a Chakra UI function that merges custom theme tokens with the library's defaults. Theme tokens are named values such as colors.brand.500 or breakpoints.md that components can reference by name instead of hardcoding pixel values or hex codes.
Install the dependency
Run this in your project root. No special permissions are required beyond write access to your local node_modules.
npm install @chakra-ui/react @emotion/react @emotion/styled framer-motion
Expected check: import { extendTheme } from '@chakra-ui/react' resolves without a module-not-found error. Risk: installing an incompatible major version can break the extendTheme API; this guide assumes Chakra UI v2.
Supported options compared
| Option | Best for | Scope | Effort |
|---|---|---|---|
extendTheme |
Global tokens reused across many components | Application-wide | Low |
Component style props (color, fontSize, bg) |
One-off styling on a single element | Single component | Low |
sx prop |
Arbitrary CSS not covered by theme tokens | Single component | Low |
| CSS custom properties | Sharing values with non-Chakra markup | Global or component | Medium |
Trade-offs to accept
extendTheme merges only the tokens you specify with Chakra's defaults, so you do not need to redefine the entire theme. The trade-off is global visibility: any component in the tree can reference brand.500, which is useful for consistency but risky if you override core tokens such as colors.gray without documenting the change. Theme changes also apply to every Chakra component that consumes those tokens, so unintended UI shifts are possible if a token name collides with an existing one.
Implementation: define custom colors, fonts, and breakpoints
Create a theme file, typically at src/theme.js or src/theme/index.js, depending on your project structure.
import { extendTheme } from '@chakra-ui/react';
const theme = extendTheme({
colors: {
brand: {
50: '#eff6ff',
100: '#dbeafe',
500: '#3b82f6',
900: '#1e3a8a',
},
},
fonts: {
heading: "'Inter', sans-serif",
body: "'Inter', sans-serif",
},
breakpoints: {
sm: '30em',
md: '48em',
lg: '62em',
xl: '80em',
'2xl': '96em',
},
});
export default theme;
Wrap your application with ChakraProvider and pass the theme. Run this in your application's entry point, such as main.jsx or App.jsx.
import { ChakraProvider } from '@chakra-ui/react';
import theme from './theme';
function App({ children }) {
return (
{children}
);
}
export default App;
Components can now consume the tokens by name. The custom breakpoints work with Chakra's responsive object syntax and the useResponsiveValue hook.
import { Box, Text } from '@chakra-ui/react';
function Card() {
return (
Brand-styled card
);
}
function ResponsivePanel() {
return (
Panel that stacks below 48em and sits side-by-side above it.
);
}
Validation: confirm the theme merged correctly
Because extendTheme is configuration rather than a state-changing operation, there is no database migration or deploy step to roll back. If the custom tokens do not appear, remove the theme prop from ChakraProvider to revert to Chakra's defaults.
Use these checks to verify the result:
- Log the resolved theme in development to confirm custom keys exist:
import theme from './theme';
console.log('Custom brand color:', theme.colors?.brand?.['500']);
console.log('Custom breakpoints:', theme.breakpoints);
- Render a component using
bg="brand.500", open browser developer tools, and inspect the computedbackground-color. It should match#3b82f6. - Resize the browser or inspect the generated CSS to confirm custom breakpoint media queries appear, such as
@media (min-width: 48em)formd.
Limitations
- Theme extensions are global. A token defined in
extendThemeis available to every Chakra component in the provider tree. - Overriding core tokens such as
colors.redcan cause unexpected style conflicts in components that rely on the original values. - Team members need to know which token names exist; otherwise they may duplicate values with inline styles.
If you are unsure whether a token should be global, start with a component-level prop. Promote it to extendTheme only after the same value appears in three or more components.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.