packages/codemod/docs/STATS_MIGRATION.md
The Stats components in Chakra UI v3 have been redesigned to use a compound component pattern with dot notation. This guide covers the automatic transformations and manual considerations when migrating.
The stats transform automatically handles:
type prop to separate components| v2 Component | v3 Component | Notes |
|---|---|---|
Stat | Stat.Root | Root container |
StatLabel | Stat.Label | Label text |
StatNumber | Stat.ValueText | Main value display |
StatHelpText | Stat.HelpText | Helper text |
StatArrow type="increase" | Stat.UpIndicator | Up arrow (no type prop) |
StatArrow type="decrease" | Stat.DownIndicator | Down arrow (no type prop) |
StatGroup | Stat.Root | Group container |
Before:
<Stat>
<StatLabel>Collected Fees</StatLabel>
<StatNumber>£0.00</StatNumber>
</Stat>
After:
<Stat.Root>
<Stat.Label>Collected Fees</Stat.Label>
<Stat.ValueText>£0.00</Stat.ValueText>
</Stat.Root>
Before:
<StatLabel>Total Sales</StatLabel>
After:
<Stat.Label>Total Sales</Stat.Label>
Before:
<StatNumber>1,234</StatNumber>
After:
<Stat.ValueText>1,234</Stat.ValueText>
Before:
<StatHelpText>Feb 12 - Feb 28</StatHelpText>
After:
<Stat.HelpText>Feb 12 - Feb 28</Stat.HelpText>
The StatArrow component with the type prop is split into two separate
components based on the direction.
Increase Arrow:
Before:
<StatHelpText>
<StatArrow type="increase" />
23.36%
</StatHelpText>
After:
<Stat.HelpText>
<Stat.UpIndicator />
23.36%
</Stat.HelpText>
Decrease Arrow:
Before:
<StatHelpText>
<StatArrow type="decrease" />
9.05%
</StatHelpText>
After:
<Stat.HelpText>
<Stat.DownIndicator />
9.05%
</Stat.HelpText>
Note: The type prop is removed and the component name changes based on the
type value.
The StatGroup component becomes Stat.Root in v3:
Before:
<StatGroup>
<Stat>
<StatLabel>Sent</StatLabel>
<StatNumber>345,670</StatNumber>
</Stat>
<Stat>
<StatLabel>Clicked</StatLabel>
<StatNumber>45</StatNumber>
</Stat>
</StatGroup>
After:
<Stat.Root>
<Stat.Root>
<Stat.Label>Sent</Stat.Label>
<Stat.ValueText>345,670</Stat.ValueText>
</Stat.Root>
<Stat.Root>
<Stat.Label>Clicked</Stat.Label>
<Stat.ValueText>45</Stat.ValueText>
</Stat.Root>
</Stat.Root>
Note: In v3, you nest multiple Stat.Root components within a parent
Stat.Root to create a group.
import {
Stat,
StatArrow,
StatGroup,
StatHelpText,
StatLabel,
StatNumber,
} from "@chakra-ui/react"
export default function App() {
return (
<>
<Stat>
<StatLabel>Collected Fees</StatLabel>
<StatNumber>£0.00</StatNumber>
<StatHelpText>Feb 12 - Feb 28</StatHelpText>
</Stat>
<StatGroup>
<Stat>
<StatLabel>Sent</StatLabel>
<StatNumber>345,670</StatNumber>
<StatHelpText>
<StatArrow type="increase" />
23.36%
</StatHelpText>
</Stat>
<Stat>
<StatLabel>Clicked</StatLabel>
<StatNumber>45</StatNumber>
<StatHelpText>
<StatArrow type="decrease" />
9.05%
</StatHelpText>
</Stat>
</StatGroup>
</>
)
}
import {
Stat,
StatArrow,
StatGroup,
StatHelpText,
StatLabel,
StatNumber,
} from "@chakra-ui/react"
export default function App() {
return (
<>
<Stat.Root>
<Stat.Label>Collected Fees</Stat.Label>
<Stat.ValueText>£0.00</Stat.ValueText>
<Stat.HelpText>Feb 12 - Feb 28</Stat.HelpText>
</Stat.Root>
<Stat.Root>
<Stat.Root>
<Stat.Label>Sent</Stat.Label>
<Stat.ValueText>345,670</Stat.ValueText>
<Stat.HelpText>
<Stat.UpIndicator />
23.36%
</Stat.HelpText>
</Stat.Root>
<Stat.Root>
<Stat.Label>Clicked</Stat.Label>
<Stat.ValueText>45</Stat.ValueText>
<Stat.HelpText>
<Stat.DownIndicator />
9.05%
</Stat.HelpText>
</Stat.Root>
</Stat.Root>
</>
)
}
All props on components are preserved during transformation:
Before:
<Stat px={4} py={2} bg="gray.100">
<StatLabel fontSize="sm">Total</StatLabel>
<StatNumber fontSize="2xl" fontWeight="bold">
1,234
</StatNumber>
</Stat>
After:
<Stat.Root px={4} py={2} bg="gray.100">
<Stat.Label fontSize="sm">Total</Stat.Label>
<Stat.ValueText fontSize="2xl" fontWeight="bold">
1,234
</Stat.ValueText>
</Stat.Root>
Props on StatArrow (except type) are also preserved:
Before:
<StatArrow type="increase" color="green.500" />
After:
<Stat.UpIndicator color="green.500" />
npx @chakra-ui/codemod@latest stats path/to/files
The codemod transforms StatGroup to Stat.Root, which means you'll have
nested Stat.Root components. Review these to ensure the structure makes sense
for your use case:
// After codemod
<Stat.Root>
{" "}
<Stat.Root>
{" "}
...
</Stat.Root>
<Stat.Root>
{" "}
...
</Stat.Root>
</Stat.Root>
You may want to add layout props to the parent Stat.Root for proper spacing:
<Stat.Root display="flex" gap={4}>
<Stat.Root>...</Stat.Root>
<Stat.Root>...</Stat.Root>
</Stat.Root>
While the codemod transforms component usage, you should update your imports to only import what you need:
Before:
import {
Stat,
StatArrow,
StatGroup,
StatHelpText,
StatLabel,
StatNumber,
} from "@chakra-ui/react"
After (v3):
import { Stat } from "@chakra-ui/react"
// All subcomponents are accessed via Stat.Label, Stat.ValueText, etc.
Or if using the snippet pattern:
import { Stat } from "@/components/ui/stat"
Before:
<Stat>
<StatLabel>Downloads</StatLabel>
<StatNumber>1,234</StatNumber>
<StatHelpText>Jan 1 - Jan 31</StatHelpText>
</Stat>
After:
<Stat.Root>
<Stat.Label>Downloads</Stat.Label>
<Stat.ValueText>1,234</Stat.ValueText>
<Stat.HelpText>Jan 1 - Jan 31</Stat.HelpText>
</Stat.Root>
Before:
<Stat>
<StatLabel>Revenue</StatLabel>
<StatNumber>$45,670</StatNumber>
<StatHelpText>
<StatArrow type="increase" />
12.5%
</StatHelpText>
</Stat>
After:
<Stat.Root>
<Stat.Label>Revenue</Stat.Label>
<Stat.ValueText>$45,670</Stat.ValueText>
<Stat.HelpText>
<Stat.UpIndicator />
12.5%
</Stat.HelpText>
</Stat.Root>
Before:
<StatGroup>
<Stat>
<StatLabel>Metric 1</StatLabel>
<StatNumber>100</StatNumber>
</Stat>
<Stat>
<StatLabel>Metric 2</StatLabel>
<StatNumber>200</StatNumber>
</Stat>
<Stat>
<StatLabel>Metric 3</StatLabel>
<StatNumber>300</StatNumber>
</Stat>
</StatGroup>
After:
<Stat.Root display="grid" gridTemplateColumns="repeat(3, 1fr)" gap={4}>
<Stat.Root>
<Stat.Label>Metric 1</Stat.Label>
<Stat.ValueText>100</Stat.ValueText>
</Stat.Root>
<Stat.Root>
<Stat.Label>Metric 2</Stat.Label>
<Stat.ValueText>200</Stat.ValueText>
</Stat.Root>
<Stat.Root>
<Stat.Label>Metric 3</Stat.Label>
<Stat.ValueText>300</Stat.ValueText>
</Stat.Root>
</Stat.Root>
The codemod only transforms Stat components imported from @chakra-ui/react.
Custom stat components are not affected:
import { Stat } from "./custom-stats"
// This will NOT be transformed
;<Stat>
<StatLabel>Custom</StatLabel>
</Stat>
If you use a dynamic value for the type prop, you'll need to manually handle
this case:
Before:
<StatArrow type={isIncrease ? "increase" : "decrease"} />
After (manual fix):
{
isIncrease ? <Stat.UpIndicator /> : <Stat.DownIndicator />
}
Problem: StatArrow wasn't transformed to Stat.UpIndicator or
Stat.DownIndicator.
Solution: Ensure the type prop is a string literal ('increase' or
'decrease'). Dynamic values require manual transformation.
Problem: After transforming StatGroup, you have nested Stat.Root
components.
Solution: This is expected behavior. Add layout props to the parent for proper spacing:
<Stat.Root display="flex" gap={4}>
<Stat.Root>...</Stat.Root>
<Stat.Root>...</Stat.Root>
</Stat.Root>
Problem: Components not found after migration.
Solution: Update imports to use the new compound component pattern:
// Remove individual imports
// import { Stat, StatLabel, StatNumber } from '@chakra-ui/react'
// Use single import
import { Stat } from "@chakra-ui/react"
StatGroup transformations and add layout props if neededStatArrow type props and manually fix