packages/codemod/docs/BUTTON_MIGRATION.md
This document outlines the migration from Chakra UI v2 Button component to v3.
| v2 Prop | v3 Prop | Notes |
|---|---|---|
isActive | data-active | Now uses data attribute |
isDisabled | disabled | Standard HTML attribute |
isLoading | loading | Simplified prop name |
| v2 Prop | v3 Prop | Notes |
|---|---|---|
colorScheme | colorPalette | Renamed for consistency |
leftIcon | (children) | Move icon as first child |
rightIcon | (children) | Move icon as last child |
iconSpacing | gap | Transformed to gap (removed if gap exists) |
variant | variant | Same, but unstyled becomes boolean prop |
variant="unstyled" → unstyled boolean prop (remove variant attribute)variant="link" → variant="plain" (renamed for clarity)solid, outline, ghost) remain the same| v2 Prop | v3 Prop | Notes |
|---|---|---|
isAttached | attached | Simplified prop name |
isDisabled | (removed) | Propagated to each Button/IconButton child instead |
Important: The codemod automatically propagates isDisabled from
ButtonGroup to all Button and IconButton children. If a child already has a
disabled prop, it won't be overridden.
v2:
import { Button } from "@chakra-ui/react"
v3:
import { Button } from "@chakra-ui/react"
No changes to imports - Button remains a named export.
v2:
import { Button } from "@chakra-ui/react"
;<Button colorScheme="blue">Click me</Button>
v3:
import { Button } from "@chakra-ui/react"
;<Button colorPalette="blue">Click me</Button>
v2:
import { Button } from '@chakra-ui/react'
<Button isActive>Active</Button>
<Button isDisabled>Disabled</Button>
<Button isLoading>Loading</Button>
v3:
import { Button } from '@chakra-ui/react'
<Button data-active>Active</Button>
<Button disabled>Disabled</Button>
<Button loading>Loading</Button>
v2:
import { Button } from "@chakra-ui/react"
import { Download } from "lucide-react"
;<Button leftIcon={<Download />} iconSpacing={4}>
Download
</Button>
v3:
import { Button } from "@chakra-ui/react"
import { Download } from "lucide-react"
;<Button gap={4}>
<Download />
Download
</Button>
v2:
import { Button } from "@chakra-ui/react"
import { ArrowRight } from "lucide-react"
;<Button rightIcon={<ArrowRight />}>Next</Button>
v3:
import { Button } from "@chakra-ui/react"
import { ArrowRight } from "lucide-react"
;<Button>
Next
<ArrowRight />
</Button>
v2:
import { Button } from "@chakra-ui/react"
import { ChevronLeft, ChevronRight } from "lucide-react"
;<Button
leftIcon={<ChevronLeft />}
rightIcon={<ChevronRight />}
iconSpacing={2}
>
Navigate
</Button>
v3:
import { Button } from "@chakra-ui/react"
import { ChevronLeft, ChevronRight } from "lucide-react"
;<Button gap={2}>
<ChevronLeft />
Navigate
<ChevronRight />
</Button>
v2:
import { Button } from "@chakra-ui/react"
;<Button variant="unstyled">Click me</Button>
v3:
import { Button } from "@chakra-ui/react"
;<Button unstyled>Click me</Button>
v2:
import { Button } from "@chakra-ui/react"
import { Download } from "lucide-react"
;<Button
colorScheme="blue"
variant="solid"
size="lg"
isLoading
leftIcon={<Download />}
iconSpacing={2}
>
Download File
</Button>
v3:
import { Button } from "@chakra-ui/react"
import { Download } from "lucide-react"
;<Button colorPalette="blue" variant="solid" size="lg" loading>
<Download />
Download File
</Button>
To automatically migrate your Button components, run:
npx @chakra-ui/codemod transform button <path>
--dry - Do a dry-run without making changes--print - Print the changed output for comparison# Transform all files in src directory
npx @chakra-ui/codemod transform button ./src
# Dry run to preview changes
npx @chakra-ui/codemod transform button ./src --dry
# Print changes for comparison
npx @chakra-ui/codemod transform button ./src --print
If you prefer to migrate manually:
Update Props:
isActive → data-activeisDisabled → disabledisLoading → loadingcolorScheme → colorPalettevariant="unstyled" → unstyled (boolean prop)Move Icons to Children:
leftIcon prop and add icon as first childrightIcon prop and add icon as last childiconSpacing prop (use gap or spacing utilities if needed)Preserve Other Props:
isActive → data-active (now uses data attribute)isDisabled → disabled (standard HTML attribute)isLoading → loading (simplified name)colorScheme → colorPalette (consistent naming)leftIcon → first child elementrightIcon → last child elementiconSpacing → removed (use gap or spacing utilities instead)variant="unstyled" → unstyled boolean prop (variant attribute removed)variant="link" → variant="plain" (renamed for clarity)isAttached → attached (simplified prop name)isDisabled → removed (automatically propagated to Button/IconButton
children)
disabled prop to each Button/IconButton
childdisabled props on children are preservedThe codemod will:
isActive, isDisabled, isLoading)colorScheme to colorPalettevariant="unstyled" to unstyled boolean propleftIcon to first child (unwrapped if JSX element)rightIcon to last child (unwrapped if JSX element)iconSpacing propv2:
import { Button, ButtonGroup } from "@chakra-ui/react"
;<ButtonGroup isAttached>
<Button>Button 1</Button>
<Button>Button 2</Button>
<Button>Button 3</Button>
</ButtonGroup>
v3:
import { Button, ButtonGroup } from "@chakra-ui/react"
;<ButtonGroup attached>
<Button>Button 1</Button>
<Button>Button 2</Button>
<Button>Button 3</Button>
</ButtonGroup>
v2:
import { Button, ButtonGroup } from "@chakra-ui/react"
;<ButtonGroup isDisabled>
<Button>Button 1</Button>
<Button>Button 2</Button>
</ButtonGroup>
v3:
import { Button, ButtonGroup } from "@chakra-ui/react"
;<ButtonGroup>
<Button disabled>Button 1</Button>
<Button disabled>Button 2</Button>
</ButtonGroup>
v2:
import { Button, ButtonGroup } from "@chakra-ui/react"
function App({ loading }) {
return (
<ButtonGroup isDisabled={loading}>
<Button>Save</Button>
<Button>Cancel</Button>
</ButtonGroup>
)
}
v3:
import { Button, ButtonGroup } from "@chakra-ui/react"
function App({ loading }) {
return (
<ButtonGroup>
<Button disabled={loading}>Save</Button>
<Button disabled={loading}>Cancel</Button>
</ButtonGroup>
)
}
v2:
import { Button, ButtonGroup, IconButton } from "@chakra-ui/react"
import { FiSettings } from "react-icons/fi"
;<ButtonGroup isDisabled isAttached>
<Button>Action</Button>
<IconButton icon={<FiSettings />} aria-label="Settings" />
</ButtonGroup>
v3:
import { Button, ButtonGroup, IconButton } from "@chakra-ui/react"
import { FiSettings } from "react-icons/fi"
;<ButtonGroup attached>
<Button disabled>Action</Button>
<IconButton icon={<FiSettings />} aria-label="Settings" disabled />
</ButtonGroup>
The v3 Button component provides:
disabled instead of isDisabled for
better HTML compliancecolorPalette aligns with other componentsis prefixdata-active attribute in v3 allows for CSS styling with [data-active]
selectorgap prop on Button or spacing
utilitiesloading state in v3 includes built-in loading spinner support{}