packages/codemod/docs/ICON_BUTTON_MIGRATION.md
This guide covers the migration of Chakra UI v2 IconButton component to the v3 API.
In v3, the IconButton component API has been updated for better consistency with React patterns. The codemod automatically handles these transformations.
icon prop removed: Icons are now passed as direct childrenisRounded → borderRadius="full": Updated prop name for clarityThe icon prop has been removed. Icons are now passed as direct children.
v2:
import { SearchIcon } from "@chakra-ui/icons"
import { IconButton } from "@chakra-ui/react"
;<IconButton icon={<SearchIcon />} aria-label="Search" />
v3:
import { SearchIcon } from "@chakra-ui/icons"
import { IconButton } from "@chakra-ui/react"
;<IconButton aria-label="Search">
<SearchIcon />
</IconButton>
Variables work the same way, just passed as children:
v2:
function MyButton({ icon }) {
return <IconButton icon={icon} aria-label="Action" />
}
v3:
function MyButton({ icon }) {
return <IconButton aria-label="Action">{icon}</IconButton>
}
The isRounded prop is renamed to borderRadius="full":
v2:
;<IconButton icon={<SearchIcon />} isRounded aria-label="Search" />
v3:
;<IconButton borderRadius="full" aria-label="Search">
<SearchIcon />
</IconButton>
Both transformations work together:
v2:
;<IconButton
icon={<CloseIcon />}
isRounded
aria-label="Close"
colorScheme="red"
size="lg"
/>
v3:
;<IconButton borderRadius="full" aria-label="Close" colorScheme="red" size="lg">
<CloseIcon />
</IconButton>
import { AddIcon, DeleteIcon, EditIcon, SearchIcon } from "@chakra-ui/icons"
import { HStack, IconButton } from "@chakra-ui/react"
function Toolbar() {
return (
<HStack spacing={4}>
<IconButton
icon={<AddIcon />}
aria-label="Add"
colorScheme="green"
isRounded
/>
<IconButton
icon={<EditIcon />}
aria-label="Edit"
colorScheme="blue"
size="lg"
/>
<IconButton
icon={<DeleteIcon />}
aria-label="Delete"
colorScheme="red"
variant="outline"
/>
<IconButton
icon={<SearchIcon />}
aria-label="Search"
isRounded
size="sm"
/>
</HStack>
)
}
import { AddIcon, DeleteIcon, EditIcon, SearchIcon } from "@chakra-ui/icons"
import { HStack, IconButton } from "@chakra-ui/react"
function Toolbar() {
return (
<HStack spacing={4}>
<IconButton aria-label="Add" colorScheme="green" borderRadius="full">
<AddIcon />
</IconButton>
<IconButton aria-label="Edit" colorScheme="blue" size="lg">
<EditIcon />
</IconButton>
<IconButton aria-label="Delete" colorScheme="red" variant="outline">
<DeleteIcon />
</IconButton>
<IconButton aria-label="Search" borderRadius="full" size="sm">
<SearchIcon />
</IconButton>
</HStack>
)
}
If you're also migrating from @chakra-ui/icons to react-icons:
v2:
import { CloseIcon, SearchIcon } from "@chakra-ui/icons"
import { IconButton } from "@chakra-ui/react"
function SearchBar() {
return (
<>
<IconButton icon={<SearchIcon />} aria-label="Search" />
<IconButton icon={<CloseIcon />} aria-label="Clear" isRounded />
</>
)
}
v3:
import { IconButton } from "@chakra-ui/react"
import { LuSearch, LuX } from "react-icons/lu"
function SearchBar() {
return (
<>
<IconButton aria-label="Search">
<LuSearch />
</IconButton>
<IconButton aria-label="Clear" borderRadius="full">
<LuX />
</IconButton>
</>
)
}
When using dynamic icons, pass them as children:
v2:
function DynamicIconButton({ iconName, ...props }) {
const iconMap = {
search: <SearchIcon />,
edit: <EditIcon />,
delete: <DeleteIcon />,
}
return <IconButton icon={iconMap[iconName]} {...props} />
}
v3:
function DynamicIconButton({ iconName, ...props }) {
const iconMap = {
search: <LuSearch />,
edit: <LuPencil />,
delete: <LuTrash2 />,
}
return <IconButton {...props}>{iconMap[iconName]}</IconButton>
}
All other IconButton props are preserved:
| Prop | v2 | v3 | Notes |
|---|---|---|---|
aria-label | ✅ | ✅ | Required prop |
colorScheme | ✅ | ✅ | Unchanged |
size | ✅ | ✅ | Unchanged |
variant | ✅ | ✅ | Unchanged |
isDisabled | ✅ | ✅ | Unchanged |
isLoading | ✅ | ✅ | Unchanged |
icon | ✅ | ❌ | → children |
isRounded | ✅ | ❌ | → borderRadius="full" |
borderRadius | ✅ | ✅ | Use instead of rounded |
| All other props | ✅ | ✅ | Unchanged |
npx @chakra-ui/codemod@latest --transform icon-button src/**/*.tsx
After running the codemod, review:
Icon size: If you were relying on the icon prop to size icons automatically, you may need to adjust icon sizes manually:
// May need size adjustment
<IconButton aria-label="Search">
<LuSearch size={20} />
</IconButton>
Custom icon components: If you have custom icon components that expect specific props, ensure they work as children:
// Custom icon wrapper
function CustomIcon({ name, ...props }) {
return <Icon as={iconMap[name]} {...props} />
}
// Usage in IconButton
;<IconButton aria-label="Action">
<CustomIcon name="search" />
</IconButton>
Conditional icons: If you're using conditional rendering for icons, ensure the logic still works:
<IconButton aria-label="Toggle">
{isOpen ? <LuChevronUp /> : <LuChevronDown />}
</IconButton>
Existing children: If an IconButton had existing children (unusual but possible), they will be replaced by the icon. Review these cases manually.
If you're also migrating from @chakra-ui/icons to react-icons/lu, run both
codemods:
# 1. Transform icons from @chakra-ui/icons
npx @chakra-ui/codemod@latest --transform icons src/**/*.tsx
# 2. Transform IconButton component
npx @chakra-ui/codemod@latest --transform icon-button src/**/*.tsx
Note: The order matters less, but running icons first ensures your icon
imports are correct before transforming the IconButton component.
Problem: Icons don't show up after migration.
Solution: Ensure icons are imported correctly:
// ✅ Correct - import the icon
import { LuSearch } from "react-icons/lu"
<IconButton aria-label="Search">
<LuSearch />
</IconButton>
// ❌ Wrong - icon not imported
<IconButton aria-label="Search">
<SearchIcon />
</IconButton>
Problem: React warns about multiple children in IconButton.
Solution: IconButton should have only one child (the icon):
// ❌ Wrong - multiple children
<IconButton aria-label="Search">
<LuSearch />
Search
</IconButton>
// ✅ Correct - single icon child
<IconButton aria-label="Search">
<LuSearch />
</IconButton>
Problem: TypeScript complains about children prop.
Solution: Ensure you're using the latest @chakra-ui/react types. The v3
IconButton types accept children.