Sprint 5 - Chakra UI v3 Migration

For the last sprint I focused on Starchart since I haven't got a response from Hurl just yet. This week I saw more and more CVEs popping up for Chakra UI v2's dependencies So I gave it a second attempt to migrate to v3. Spoiler alert: It was a nightmare. [WIP] Upgrade chakra-ui to v3 #895 theoforger posted on Apr 03, 2025 Description chakra-ui version 3 introduced many breaking changes. This PR is an attempt to upgrade Changes Removed @emotion/styled, framer-motion, @chakra-ui/icons(migrated to react-icons since chakra stopped supporting their icons library) Modified tsconfig.json to target ESNext. Add code snippet from chakra Refactored theme to use systems instead Changed component names and structures (the migration guide is not complete on this matter) Dropped useToast hook in favor of toaster from the code snippet View on GitHub What Changes Did I Encounter? In short, everything has changed. From dependencies, components, props, to syntax, configuration schema, even font size and theme. It was essentially a rewrite. Dependencies Chakra UI v3 doesn't rely on framer-motion for animation anymore. It needed to be removed, among some other changes npm uninstall @emotion/styled framer-motion npm install @chakra-ui/react@latest @emotion/react@latest They also introduced some code snippet to supplement some of the changes in this update. I'll go through them later, but here's how you add the snippet: npx @chakra-ui/cli snippet add Component Names and Behavior Component Changes happened all across the board. Generally, namespaces are used to replace child components. Some are simple name changes, for example: v2 v3 However, many of them also has different behavior and expect different structures. For instance: v2 v3 One Two Three one! two! three! one two three one! two! three! As you can see, Tabs in v2 sequentially maps a from to in , while in v3 it requires a value, in addition to all the name changes. There are many other changes like these. Unfortunately the only way to handle them is to look at the documentation for both versions and compare the differences. Props There are changes in both the name of some props, and what props are expected for certain components. For one, some boolean typed props now have a simpler name. For example, isOpen became open. The other type of change is also the more challenging type. For example the component changed the available variants you can use, and silently dropped support for some styling props like align. Some of them are related to some other grand schema changes, but just like the components, the only way to figure them out is to compare the documentation. Theme Configuration In Chakra UI v3, themes are included as a part of system, as apposed to a standalone configuration option in v2. The new theme object expects a completely different schema too. In addition, component-specific style override in v2 is replaced by recipes. So for the Starchart project, the configuration went from: const theme = extendTheme( { styles, colors, breakpoints, components: { Link: defineStyleConfig({ baseStyle: { color: 'brand.500', textDecor: 'underline', }, }), }, }, withDefaultColorScheme({ colorScheme: 'brand' }) ); to const theme = createSystem(defaultConfig, { theme: { recipes: { link: defineRecipe({ base: { textDecor: 'underline', }, }), }, tokens: { colors, breakpoints, }, semanticTokens: { colors: { brand: { solid: { value: '{colors.brand.500}' }, contrast: { value: 'white' }, 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}' }, }, brand_gray: { solid: { value: '{colors.brand_gray.500}' }, contrast: { value: 'colors.brand_gray.100' }, fg: { value: '{colors.brand_gray.700}' }, muted: { value: '{colors.brand_gray.100}' }, subtle: { value: '{colors.brand_gray.200}' }, emphasized: { value: '{colors.brand_gray.300}' }, focusR

Apr 16, 2025 - 22:15
 0
Sprint 5 - Chakra UI v3 Migration

For the last sprint I focused on Starchart since I haven't got a response from Hurl just yet. This week I saw more and more CVEs popping up for Chakra UI v2's dependencies So I gave it a second attempt to migrate to v3. Spoiler alert: It was a nightmare.

[WIP] Upgrade chakra-ui to v3 #895

Description

chakra-ui version 3 introduced many breaking changes. This PR is an attempt to upgrade

Changes

  • Removed @emotion/styled, framer-motion, @chakra-ui/icons(migrated to react-icons since chakra stopped supporting their icons library)
  • Modified tsconfig.json to target ESNext.
  • Add code snippet from chakra
  • Refactored theme to use systems instead
  • Changed component names and structures (the migration guide is not complete on this matter)
  • Dropped useToast hook in favor of toaster from the code snippet

What Changes Did I Encounter?

In short, everything has changed. From dependencies, components, props, to syntax, configuration schema, even font size and theme. It was essentially a rewrite.

Dependencies

Chakra UI v3 doesn't rely on framer-motion for animation anymore. It needed to be removed, among some other changes

npm uninstall @emotion/styled framer-motion
npm install @chakra-ui/react@latest @emotion/react@latest

They also introduced some code snippet to supplement some of the changes in this update. I'll go through them later, but here's how you add the snippet:

npx @chakra-ui/cli snippet add

Component Names and Behavior

Component Changes happened all across the board. Generally, namespaces are used to replace child components. Some are simple name changes, for example:

v2 v3

  

  
    
      
    
  
  
    
      
    
  
  
    
      
    
  

      

However, many of them also has different behavior and expect different structures. For instance:

v2 v3

  
    One
    Two
    Three
  

  
    
      

one!

two!

three!


  
    
      one
    
    
      two
    
    
      three
    
  
  one!
  two!
  three!

As you can see, Tabs in v2 sequentially maps a from to in , while in v3 it requires a value, in addition to all the name changes.

There are many other changes like these. Unfortunately the only way to handle them is to look at the documentation for both versions and compare the differences.

Props

There are changes in both the name of some props, and what props are expected for certain components.

For one, some boolean typed props now have a simpler name. For example, isOpen became open.

The other type of change is also the more challenging type. For example the component changed the available variants you can use, and silently dropped support for some styling props like align. Some of them are related to some other grand schema changes, but just like the components, the only way to figure them out is to compare the documentation.

Theme Configuration

In Chakra UI v3, themes are included as a part of system, as apposed to a standalone configuration option in v2. The new theme object expects a completely different schema too.

In addition, component-specific style override in v2 is replaced by recipes.

So for the Starchart project, the configuration went from:

const theme = extendTheme(
  {
    styles,
    colors,
    breakpoints,
    components: {
      Link: defineStyleConfig({
        baseStyle: {
          color: 'brand.500',
          textDecor: 'underline',
        },
      }),
    },
  },
  withDefaultColorScheme({ colorScheme: 'brand' })
);

to

const theme = createSystem(defaultConfig, {
  theme: {
    recipes: {
      link: defineRecipe({
        base: {
          textDecor: 'underline',
        },
      }),
    },
    tokens: {
      colors,
      breakpoints,
    },
    semanticTokens: {
      colors: {
        brand: {
          solid: { value: '{colors.brand.500}' },
          contrast: { value: 'white' },
          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}' },
        },
        brand_gray: {
          solid: { value: '{colors.brand_gray.500}' },
          contrast: { value: 'colors.brand_gray.100' },
          fg: { value: '{colors.brand_gray.700}' },
          muted: { value: '{colors.brand_gray.100}' },
          subtle: { value: '{colors.brand_gray.200}' },
          emphasized: { value: '{colors.brand_gray.300}' },
          focusRing: { value: '{colors.brand_gray.500}' },
        },
      },
    },
  },
  globalCss: styles,
});

Toast

In Chakra UI v2, Toast is used via a hook. However, in v3 it's replaced by the toaster code snippet. In the new version, you need to import both Toaster and toaster from the snippet, place the component somewhere on the page, and then use toaster to trigger them. For example:

import { Toaster, toaster } from '~/components/ui/toaster';
...
  useEffect(() => {
    if (clipboard.copied) {
      toaster.create({
        title: `${title} was copied to the clipboard`,
        type: 'success',
      });
    }
  }, [title, clipboard.copied]);
...
return (
  <>
    // page content...
    <Toaster />
  <>
)

Dropping chakra-ui/icon

@chakra-ui/icons is deprecated in Chakra UI v3. There are a couple of replacements but I decided to migrate to react-icons, since it was already in use for other parts of the project.

To migrate, you need to wrap the icon component from your library of choice with .... For example:

// Download icon
<Icon fontSize="md" onClick={handler}>
  <FaDownload />
Icon>

What's Still Broken?

Custom Breakpoints

In Chakra UI, you can define custom breakpoints like so:

const breakpoints = {
  'xs': { value: '20em' },
  'sm': { value: '30em' },
  'md': { value: '48em' },
  'lg': { value: '62em' },
  'xl': { value: '80em' },
  '2xl': { value: '96em' },
};

However, despite including this configuration in my custom theme, I still get type error in places where custom breakpoints are used:

GitHub Actions error

Animation

Animation is broken after this upgrade, possibly due to the deprecation of framer-motion. However, from my testing, the animation issue does not seem to persist once React is updated to 19.

Mobile Layout

Other than some inconsistent breakpoints behavior, some UI elements are not in the correct place in mobile layout. For example:

Before After
before after

The Real Problem

The most difficult aspect of this migration was not the changes themselves. It was the lack of documentation for them. Although they provide a migration guide, it's far from complete.

Just to name a few:

  1. The guide doesn't cover most changes in the component names. Some components have completely overhauled their structures (For example ), and it's not mentioned either.
  2. Many components changed the props they expect, most of which are not mentioned in the guide.
  3. went from a hook to a code snippet, and it's not mentioned.
  4. Font sizes are completely changed, which is not mentioned in the guide.
  5. component is removed and the behavior changed in as well. Neither of them is documented.
  6. Component-specific style override is replaced by recipes. It's not covered by the guide. ...

Of course, this section is not meant as an attack on the Chakra UI project, but a reminder that a significant upgrade like this really needs a comprehensive migration guide. An automation tool would also be nice, like what React did with react-codemod.