🎉 Black Friday Sale: Over 30% off Premium Chakra UI Components
Shop NowNovember 19, 2025
Optimizing styling performance is crucial for maintaining smooth user experiences, especially in complex applications. This guide covers best practices for styling components in Chakra UI with a focus on performance.
Dynamic styling through inline CSS props can impact performance in several ways:
// ❌ Avoid: Dynamic styles recalculated on every render
const Component = ({ isActive, size }) => {
return (
<Box
padding={isActive ? "8" : "4"}
background={isActive ? "blue.500" : "gray.100"}
fontSize={size === "large" ? "xl" : "md"}
>
Content
</Box>
)
}Data attributes provide a performant way to handle state-based styling without dynamic CSS props. The styles are pre-compiled and don't change at runtime.
// ✅ Better: Use data attributes with static styles
const Component = ({ isActive, isDisabled }) => {
return (
<Box
data-active={isActive || undefined}
data-disabled={isDisabled || undefined}
css={{
padding: "4",
background: "gray.100",
fontSize: "md",
"&[data-active]": {
padding: "8",
background: "blue.500",
},
"&[data-disabled]": {
opacity: 0.5,
cursor: "not-allowed",
},
}}
>
Content
</Box>
)
}For truly dynamic values (like animations or user-controlled properties), use CSS variables instead of inline styles.
// ✅ Better: CSS variables for dynamic values
const ProgressBar = ({ progress }) => {
return (
<Box
style={{ "--progress": `${progress}%` }}
css={{
width: "100%",
height: "8px",
background: "gray.200",
"&::before": {
content: '""',
display: "block",
width: "var(--progress)",
height: "100%",
background: "blue.500",
transition: "width 0.3s ease",
},
}}
></Box>
)
}Recipes provide the most performant way to handle variant-based styling. All styles are pre-compiled and optimized at build time.
// ✅ Best: Use recipes for variants
import { createRecipeContext, defineRecipe } from "@chakra-ui/react"
const cardRecipe = defineRecipe({
className: "card",
base: {
padding: "4",
borderRadius: "md",
transition: "all 0.2s",
},
variants: {
variant: {
elevated: {
boxShadow: "md",
background: "white",
},
outline: {
borderWidth: "1px",
borderColor: "gray.200",
},
},
size: {
sm: { padding: "2" },
md: { padding: "4" },
lg: { padding: "6" },
},
isActive: {
true: {
borderColor: "blue.500",
background: "blue.50",
},
},
},
compoundVariants: [
{
variant: "elevated",
isActive: true,
css: {
boxShadow: "lg",
transform: "translateY(-2px)",
},
},
],
})
// Create component with recipe context
const { withContext } = createRecipeContext({ recipe: cardRecipe })
// Usage - variant props are passed directly
const Card = withContext<HTMLDivElement, CardProps>("div")
// In your app
const App = () => (
<Card variant="elevated" size="lg" isActive>
Content
</Card>
)For single dynamic values that don't fit into variants, use the style attribute sparingly with CSS variables.
// ✅ OK for one-off dynamic values
const CustomComponent = ({ rotation, scale }) => {
return (
<Box
transform="rotate(var(--rotation)) scale(var(--scale))"
transition="transform 0.3s ease"
style={{ "--rotation": `${rotation}deg`, "--scale": scale }}
>
Content
</Box>
)
}Before shipping your component, consider:
If your application requires absolute zero runtime CSS-in-JS overhead, consider using Panda CSS with Ark UI as an alternative stack:
Panda CSS is a build-time CSS-in-JS solution that
generates static CSS files with zero runtime overhead. You can use the
@chakra-ui/panda-preset to get all of Chakra UI's design tokens, recipes, and
patterns in a zero-runtime environment.
# Install dependencies
npm install -D @pandacss/dev @chakra-ui/panda-preset// panda.config.ts
import { defineConfig } from "@pandacss/dev"
export default defineConfig({
presets: ["@chakra-ui/panda-preset"],
include: ["./src/**/*.{js,jsx,ts,tsx}"],
outdir: "styled-system",
})// Use Chakra UI recipes with zero runtime
import { css } from "styled-system/css"
import { hstack, vstack } from "styled-system/patterns"
import { button, card } from "styled-system/recipes"
function App() {
return (
<div className={vstack({ gap: "4" })}>
<button className={button({ variant: "solid", size: "lg" })}>
Click me
</button>
<div className={card({ variant: "outline" })}>Card content</div>
</div>
)
}For unstyled, accessible components with zero runtime, combine Panda CSS with Ark UI:
import { Dialog } from "@ark-ui/react/dialog"
import { button, dialog } from "styled-system/recipes"
const styles = dialog({ size: "md" })
export const Modal = () => {
return (
<Dialog.Root>
<Dialog.Trigger className={button({ variant: "solid", size: "lg" })}>
Open
</Dialog.Trigger>
<Dialog.Positioner className={styles.positioner}>
<Dialog.Content className={styles.content}>
{/* Your content */}
</Dialog.Content>
</Dialog.Positioner>
</Dialog.Root>
)
}By following these patterns, you'll create applications that are not only fast but also maintainable and scalable. The key is to move styling logic from runtime to build time whenever possible.