Documentation for migrating to Chakra UI v3. # Migration to v3 :::warning We recommend using the [LLMs.txt](/docs/get-started/llms) files to make the Chakra UI v3 documentation available to large language models. ::: ## Steps > The minimum node version required is Node.20.x :::steps ### Update Packages Remove the unused packages: `@emotion/styled` and `framer-motion`. These packages are no longer required in Chakra UI. ```bash npm uninstall @emotion/styled framer-motion ``` Install updated versions of the packages: `@chakra-ui/react` and `@emotion/react`. ```bash npm install @chakra-ui/react@latest @emotion/react@latest ``` Next, install component snippets using the CLI snippets. Snippets provide pre-built compositions of Chakra components to save you time and put you in charge. ```bash npx @chakra-ui/cli snippet add ``` ### Refactor Custom Theme Move your custom theme to a dedicated `theme.js` or `theme.ts` file. Use `createSystem` and `defaultConfig` to configure your theme. **Before** ```ts import { extendTheme } from "@chakra-ui/react" export const theme = extendTheme({ fonts: { heading: `'Figtree', sans-serif`, body: `'Figtree', sans-serif`, }, }) ``` **After** ```ts {3} import { createSystem, defaultConfig } from "@chakra-ui/react" export const system = createSystem(defaultConfig, { theme: { tokens: { fonts: { heading: { value: `'Figtree', sans-serif` }, body: { value: `'Figtree', sans-serif` }, }, }, }, }) ``` > All token values need to be wrapped in an object with a **value** key. Learn > more about tokens [here](/docs/theming/tokens). ### Update ChakraProvider Update the ChakraProvider import from `@chakra-ui/react` to the one from the snippets. Next, rename the `theme` prop to `value` to match the new system-based theming approach. **Before** ```tsx import { ChakraProvider } from "@chakra-ui/react" export const App = ({ Component }) => ( ) ``` **After** ```tsx {1,3} import { Provider } from "@/components/ui/provider" import { defaultSystem } from "@chakra-ui/react" export const App = ({ Component }) => ( ) ``` ```tsx {1,3} import { ColorModeProvider } from "@/components/ui/color-mode" import { ChakraProvider, defaultSystem } from "@chakra-ui/react" export function Provider(props) { return ( ) } ``` > If you have a custom theme, replace `defaultSystem` with the custom `system` The Provider component compose the `ChakraProvider` from Chakra and `ThemeProvider` from `next-themes` ::: ## Improvements - **Performance:** Improved reconciliation performance by `4x` and re-render performance by `1.6x` - **Namespaced imports:** Import components using the dot notation for more concise imports ```tsx import { Accordion } from "@chakra-ui/react" const Demo = () => { return ( ) } ``` - **TypeScript:** Improved IntelliSense and type inference for style props and tokens. - **Polymorphism:** Loosened the `as` prop typings in favor of using the `asChild` prop. This pattern was inspired by Radix Primitives and Ark UI. ## Removed Features ### Color Mode - `ColorModeProvider` and `useColorMode` have been removed in favor of `next-themes` - `LightMode`, `DarkMode` and `ColorModeScript` components have been removed. You now have to use `className="light"` or `className="dark"` to force themes. - `useColorModeValue` has been removed in favor of `useTheme` from `next-themes` :::note We provide snippets for color mode via the CLI to help you set up color mode quickly using `next-themes` ::: ### Hooks We removed the hooks package in favor of using dedicated, robust libraries like `react-use` and `usehooks-ts` The only hooks we ship now are `useBreakpointValue`, `useCallbackRef`, `useDisclosure`, `useControllableState` and `useMediaQuery`. ### Style Config We removed the `styleConfig` and `multiStyleConfig` concept in favor of recipes and slot recipes. This pattern was inspired by Panda CSS. ### Next.js package We've removed the `@chakra-ui/next-js` package in favor of using the `asChild` prop for better flexibility. To style the Next.js image component, use the `asChild` prop on the `Box` component. ```jsx ``` To style the Next.js link component, use the `asChild` prop on the `Link` component ```jsx ``` ### Theme Tools We've removed this package in favor using CSS color mix. **Before** We used JS to resolve the colors and then apply the transparency ```jsx defineStyle({ bg: transparentize("blue.200", 0.16)(theme), // -> rgba(0, 0, 255, 0.16) }) ``` **After** We now use CSS color-mix ```jsx defineStyle({ bg: "blue.200/16", // -> color-mix(in srgb, var(--chakra-colors-200), transparent 16%) }) ``` ### forwardRef Due to the simplification of the `as` prop, we no longer provide a custom `forwardRef`. Prefer to use `forwardRef` from React directly. Before: ```tsx {3} import { Button as ChakraButton, forwardRef } from "@chakra-ui/react" const Button = forwardRef(function Button(props, ref) { return }) ``` After: ```tsx {2, 4} import { Button as ChakraButton } from "@chakra-ui/react" import { forwardRef } from "react" const Button = forwardRef( function Button(props, ref) { return }, ) ``` ### Icons Removed `@chakra-ui/icons` package. Prefer to use `lucide-react` or `react-icons` instead. ### Storybook Addon We're removed the storybook addon in favor of using `@storybook/addon-themes` and `withThemeByClassName` helper. ```tsx import { ChakraProvider, defaultSystem } from "@chakra-ui/react" import { withThemeByClassName } from "@storybook/addon-themes" import type { Preview, ReactRenderer } from "@storybook/react" const preview: Preview = { decorators: [ withThemeByClassName({ defaultTheme: "light", themes: { light: "", dark: "dark", }, }), (Story) => ( ), ], } export default preview ``` ### Removed Components - **StackItem**: You don't need this anymore. Use `Box` instead. - **FocusLock**: We no longer ship a focus lock component. Install and use `react-focus-lock` directly. - **AlertDialog** - Replace with the `Dialog` component and set `role=alertdialog` - Set `leastDestructiveRef` prop to the `initialFocusEl` to the `Dialog.Root` component ### CircularProgress - Renamed to `ProgressCircle` and now uses compound components - `isIndeterminate` becomes `value={null}` - `thickness` prop becomes `--thickness` CSS variable - `color` prop becomes `stroke` prop on `ProgressCircle.Range` Before: ```tsx ``` After: ```tsx ``` For indeterminate progress: ```tsx ``` ### StackDivider - No longer available as a separate component - Use explicit `Stack.Separator` components between stack items Before: ```tsx } spacing={4}> Item 1 Item 2 Item 3 ``` After: ```tsx Item 1 Item 2 Item 3 ``` ## Prop Changes ### Boolean Props Changed naming convention for boolean properties from `is` to `` - `isOpen` -> `open` - `defaultIsOpen` -> `defaultOpen` - `isDisabled` -> `disabled` - `isInvalid` -> `invalid` - `isRequired` -> `required` ### ColorScheme Prop The `colorScheme` prop has been changed to `colorPalette` **Before** - You could only use `colorScheme` in a component's theme - `colorScheme` clashes with the native `colorScheme` prop in HTML elements ```tsx ``` **After** - You can now use `colorPalette` anywhere ```tsx ``` Usage in any component, you can do something like: ```tsx Some box Some text ``` If you are using custom colors, you must define two things to make `colorPalette` work: - **tokens**: For the 50-950 color palette - **semanticTokens**: For the `solid`, `contrast`, `fg`, `muted`, `subtle`, `emphasized`, and `focusRing` color keys ```tsx title="theme.ts" /brand: {/ /tokens: {/ /semanticTokens: {/ import { createSystem, defaultConfig } from "@chakra-ui/react" export const system = createSystem(defaultConfig, { theme: { tokens: { colors: { brand: { 50: { value: "#e6f2ff" }, 100: { value: "#e6f2ff" }, 200: { value: "#bfdeff" }, 300: { value: "#99caff" }, // ... 950: { value: "#001a33" }, }, }, }, semanticTokens: { colors: { brand: { solid: { value: "{colors.brand.500}" }, contrast: { value: "{colors.brand.100}" }, fg: { value: "{colors.brand.700}" }, muted: { value: "{colors.brand.100}" }, subtle: { value: "{colors.brand.200}" }, emphasized: { value: "{colors.brand.300}" }, focusRing: { value: "{colors.brand.500}" }, }, }, }, }, }) ``` > Read more about it [here](/guides/theming-custom-colors). ### Gradient Props Gradient style prop simplified to `gradient` and `gradientFrom` and `gradientTo` props. This reduces the runtime performance cost of parsing the gradient string, and allows for better type inference. **Before** ```tsx ``` **After** ```tsx ``` ### Color Palette - Default color palette is now `gray` for all components but you can configure this in your theme. - Default theme color palette size has been increased to 11 shades to allow more color variations. **Before** ```tsx const colors = { // ... gray: { 50: "#F7FAFC", 100: "#EDF2F7", 200: "#E2E8F0", 300: "#CBD5E0", 400: "#A0AEC0", 500: "#718096", 600: "#4A5568", 700: "#2D3748", 800: "#1A202C", 900: "#171923", }, } ``` **After** ```tsx const colors = { // ... gray: { 50: { value: "#fafafa" }, 100: { value: "#f4f4f5" }, 200: { value: "#e4e4e7" }, 300: { value: "#d4d4d8" }, 400: { value: "#a1a1aa" }, 500: { value: "#71717a" }, 600: { value: "#52525b" }, 700: { value: "#3f3f46" }, 800: { value: "#27272a" }, 900: { value: "#18181b" }, 950: { value: "#09090b" }, }, } ``` ### Style Props Changed the naming convention for some style props - `noOfLines` -> `lineClamp` - `truncated` -> `truncate` - `_activeLink` -> `_currentPage` - `_activeStep` -> `_currentStep` - `_mediaDark` -> `_osDark` - `_mediaLight` -> `_osLight` **Examples:** ```tsx // Before Long text that will be clamped to 2 lines This text will be truncated with ellipsis // After Long text that will be clamped to 2 lines This text will be truncated with ellipsis ``` We removed the `apply` prop in favor of `textStyle` or `layerStyles` ### Nested Styles We have changed the way you write nested styles in Chakra UI components. **Before** Write nested styles using the `sx` or `__css` prop, and you sometimes don't get auto-completion for nested styles. ```tsx ``` **After** Write nested styles using the `css` prop. All nested selectors **require** the use of the ampersand `&` prefix ```tsx ``` This was done for two reasons: - **Faster style processing:** Before we had to check if a style key is a style prop or a selector which is quite expensive overall. - **Better typings:** This makes it easier to type nested style props are strongly typed ## Component Changes ### ChakraProvider - Removed `theme` prop in favor of passing the `system` prop instead. Import the `defaultSystem` module instead of `theme` - Removed `resetCss` prop in favor of passing `preflight: false` to the `createSystem` function Before ```tsx ``` After ```tsx const system = createSystem(defaultConfig, { preflight: false }) ``` - Removed support for configuring toast options. Pass it to the `createToaster` function in `components/ui/toaster.tsx` file instead. ### Modal - Renamed to `Dialog` - Remove `isCentered` prop in favor of using the `placement=center` prop - Removed `isOpen` and `onClose` props in favor of using the `open` and `onOpenChange` props ### Avatar - Remove `max` prop in favor of userland control - Remove excess label part - Move image related props to `Avatar.Image` component - Move fallback icon to `Avatar.Fallback` component - Move `name` prop to `Avatar.Fallback` component ### Portal - Remove `appendToParentPortal` prop in favor of using the `containerRef` - Remove `PortalManager` component ### Progress - Now uses compound components with `Progress.Root`, `Progress.Track`, and `Progress.Range` - `hasStripe` prop renamed to `striped` - `isAnimated` prop renamed to `animated` - `colorScheme` prop renamed to `colorPalette` Before: ```tsx ``` After: ```tsx ``` ### Stack - Changed `spacing` to `gap` - Removed `StackItem` in favor of using the `Box` component directly ### Select Now called `NativeSelect` and exposes all parts now. Before: ```tsx ``` After: ```tsx ``` Changing the icon Before: ```tsx ``` After ```tsx Email This field is required ``` ### Link - Removed `isExternal` prop in favor of explicitly setting the `target` and `rel` props Before ```tsx Click me ``` After ```tsx Click me ``` ### Button - Removed `isActive` in favor of passing `data-active` Before ```tsx ``` After ```tsx ``` ### IconButton - Removed `icon` prop in favor of rendering the `children` prop directly - Removed `isRounded` in favor of using the `borderRadius=full` prop ### Spinner - Change the `thickness` prop to `borderWidth` - Change the `speed` prop to `animationDuration` Before ```tsx ``` After ```tsx ``` ### Dialog, Drawer - `isOpen` and `onChange` props have been removed in favor of `open` and `onOpenChange` props - `blockScrollOnMount` is now `preventScroll` - `closeOnEsc` is now `closeOnEscape` - `closeOnOverlayClick` is now `closeOnInteractOutside` - `initialFocusRef` is now an `initialFocusEl` function that returns the element - `finalFocusRef` is now an `finalFocusEl` function that returns the element ### Editable - `finalFocusRef` is now `finalFocusEl` function that returns the element - `isDisabled` is now `disabled` - `onSubmit` is now `onValueCommit` - `onCancel` is now `onValueRevert` - `onChange` is now `onValueChange` - `startWithEditView` is now `defaultEdit` - Replace `submitOnBlur` with `submitMode` ### FormControl - Replace `FormControl` with the `Field` component. - Replace `FormErrorMessage` with the `Field.ErrorText` component. Before: ```tsx This field is required ``` After: ```tsx This field is required ``` ### Collapse Replace with the `Collapsible` component. Before: ```tsx Some content ``` After: ```tsx Some content ``` ### Slider - `onChange` prop is now called `onValueChange` - `onChangeEnd` prop is now called `onValueChangeEnd` - `onChangeStart` prop is now removed - `isReversed` prop is now removed ### RangeSlider Can now be used as a single slider by passing an array of values Before: ```tsx ``` After: ```tsx ``` ### Table - `TableContainer` is now `Table.ScrollArea` - `Td`(now called `Table.ColumnHeader`) `isNumeric` is now `textAlign="end"` The compound component have been renamed slightly. Before: ```tsx Imperial to metric conversion factors {items.map((item) => ( ))}
Product Category Price
{item.name} {item.category} {item.price}
Product Category Price
``` After: ```tsx Product Category Price {items.map((item) => ( {item.name} {item.category} {item.price} ))} ``` ### Tag `TagLeftIcon` and `TagRightIcon` are now `Tag.StartElement` and `Tag.EndElement` Before: ```tsx Cyan ``` After: ```tsx Cyan ``` - `TagCloseButton` is now `Tag.CloseTrigger` Before: ```tsx Green ``` After: ```tsx Green ``` ### Alert - `AlertIcon` is now `Alert.Indicator` Before: ```tsx Your browser is outdated! Your Chakra experience may be degraded. ``` After: ```tsx Invalid Fields Your form has some errors. Please fix them and try again. ``` - Removed `addRole`prop in favor of `role` prop. ### Skeleton - `startColor` and `endColor` props now use CSS variables Before: ```tsx ``` After: ```tsx ``` - `isLoaded` prop is now `loading` Before: ```tsx Chakra ui is cool ``` After: ```tsx Chakra ui is cool ``` ### Menu - Now uses compound components everywhere Before: ```tsx }> Actions Download Create a Copy ``` After: ```tsx Download Create a Copy ``` - Accesing internal state is now done via `Menu.Context` no longer render prop. Before: ```tsx {({ isOpen }) => ( <> }> {isOpen ? "Close" : "Open"} Download alert("Kagebunshin")}>Create a Copy )} ``` After: ```tsx {(menu) => ( )} Download alert("Kagebunshin")}> Create a Copy ``` - `isLazy` prop on `Menu` is split into `lazyMount` and `unmountOnExit` on `Menu.Root` - `MenuOptionGroup` is now split into `Menu.RadioItemGroup` and `Menu.CheckboxItemGroup` to handle the states separately. Before: ```tsx Trigger Ascending Descending Email Phone Country ``` After: ```tsx Ascending Descending Email Phone Country ``` ### Tooltip - `closeOnEsc` now renamed to `closeOnEscape` - `closeOnMouseDown` is now `closeOnPointerDown` - `placement`, `gutter`, `offset` and `arrow` on `Tooltip` is now included as `positioning` prop on `Tooltip.Root` Before: ```tsx ``` After: ```tsx ``` ### Accordion - These props have been changed: - `allowMultiple` -> `multiple` - `allowToggle` -> `collapsible` - `index` -> `value` - `defaultIndex` -> `defaultValue` Before: ```tsx {}} /> ``` After: ```tsx {}} /> ``` - `AccordionButton` is now `Accordion.Trigger` - `AccordionIcon` is now `Accordion.ItemIndicator` Before: ```tsx Section 1 title ``` After: ```tsx Section 1 title ``` ### Tabs - Component structure has changed and `value` prop is now required on list and panels. Before: ```tsx One Two Three one! two! three! ``` After: ```tsx One Two Three one! two! three! ``` - `defaultIndex`, `index` and `onChange` is now `defaultValue`, `value` and `onValueChange` respectively Before: ```tsx {}} /> ``` After: ```tsx {}} /> ``` - `isLazy` prop on `Tabs` is now `lazyMount` and `unmountOnExit` on `Tabs.Root` Before: ```tsx ``` After: ```tsx ``` ### Show and Hide - `Show` and `Hide` components are removed in favor of `hideFrom` and `hideBelow` Before: ```tsx This text appears only on screens md and smaller. This text hides at the "md" value screen width and smaller. ``` After: ```tsx This text hides at the "md" value screen width and smaller. This text appears only on screens md and larger. ``` ### Checkbox - Refactored to use compound components Before: ```tsx Checkbox ``` After: ```tsx Checkbox ``` ### Radio Group - Refactored to use compound components Before: ```tsx Radio Radio ``` After: ```tsx ``` ### Button Props - `isActive` → `data-active` attribute - `isDisabled` → `disabled` - `isLoading` → `loading` - `leftIcon` and `rightIcon` → passed as children - `iconSpacing` → removed (use gap in flex layout) - `colorScheme` → `colorPalette` **Example:** ```tsx // Before // After ``` ### Input Props - `isDisabled` → `disabled` - `isInvalid` → `invalid` - `isReadOnly` → `readOnly` - `isRequired` → `required` - `colorScheme` → `colorPalette` - `focusBorderColor` → use CSS variables - `errorBorderColor` → use CSS variables **Example:** ```tsx // Before // After ``` ### Checkbox Props - `isChecked` → `checked` - `isDisabled` → `disabled` - `isInvalid` → `invalid` - `isIndeterminate` → `indeterminate` (on Indicator) - `colorScheme` → `colorPalette` - `iconColor` → removed (use CSS) - `iconSize` → removed (use CSS) - `spacing` → removed (use gap) **Example:** ```tsx // Before Accept terms // After Accept terms ``` ### Modal to Dialog Props - `isOpen` → `open` - `onClose` → `onOpenChange` (different signature) - `isCentered` → `placement="center"` - `scrollBehavior` → same - `motionPreset` → updated values (e.g., `slideInBottom` → `slide-in-bottom`) - `closeOnOverlayClick` → `closeOnInteractOutside` - `closeOnEsc` → `closeOnEscape` - `blockScrollOnMount` → `preventScroll` - `returnFocusOnClose` → `restoreFocus` - `initialFocusRef` → `initialFocusEl` (function) - `finalFocusRef` → `finalFocusEl` (function) **Example:** ```tsx // Before Title Content // After !e.open && onClose()} placement="center" closeOnInteractOutside={true} initialFocusEl={() => initialRef.current} > Title Content ``` ### Stack Props - `spacing` → `gap` - `divider` → `separator` - Other props remain the same **Example:** ```tsx // Before } > Item 1 Item 2 // After } > Item 1 Item 2 ```