Update chakra-ui v2 to v3 to support React19, Next15

React 19, Next 15 にアップデートしたら Chakura-ui v2 の page.tsx で呼び出している <ChakraProvider>
の部分で延々とエラーが発生したので Chakura-ui を v3 にアップデートする
import { Provider } from './Provider.tsx';
export default async function Page() {
return (<Provider><PageRoot /></Provider>);
}
import { FC, ReactNode } from "react";
import { ChakraProvider } from "@chakra-ui/react";
type ProvidersProps = {
children: ReactNode;
};
export const Provider: FC<Readonly<ProvidersProps>> = ({ children }) => (
<ChakraProvider>{children}</ChakraProvider>
);
Page に "use client"
をつけて client component にしても変わらず

環境
npm list
- react
19.0.0
- react-dom
19.0.0
- next
15.1.2
- typescript
5.7.2
Chakra-ui を v3 にアップデートする
@chakra-ui/icons ^2.1.1 → ^2.2.4
@chakra-ui/next-js ^2.2.0 → ^2.4.2
@chakra-ui/react ^2.8.2 → ^3.3.0
上記のようにパッケージをアップデートした
Next.js の場合 ChakraProvider は クライアントコンポーネントでないとエラーになる
先のエラーは <ChakraProvider>
がクライアントコンポーネントでなかったことで発生していたっぽい
+ "use client";
import { FC, ReactNode } from "react";
import { ChakraProvider } from "@chakra-ui/react";
type ProvidersProps = {
children: ReactNode;
};
export const Provider: FC<Readonly<ProvidersProps>> = ({ children }) => (
<ChakraProvider>{children}</ChakraProvider>
);
ChakraProvider に value が必須になっていたので修正する
Property 'value' is missing in type '{ children: ReactNode; }' but required in type 'ChakraProviderProps'.ts(2741)
- import { ChakraProvider } from "@chakra-ui/react";
+ import { ChakraProvider, defaultSystem } from "@chakra-ui/react";
type ProvidersProps = {
children: ReactNode;
};
export const Providers: FC<Readonly<ProvidersProps>> = ({ children }) => (
- <ChakraProvider>{children}</ChakraProvider>
+ <ChakraProvider value={defaultSystem}>{children}</ChakraProvider>
);
cf. https://github.com/chakra-ui/chakra-ui/blob/main/sandbox/next-app/app/provider.tsx
next.config.mjs に設定を追加する
Optimize Bundle
We recommend using the experimental.optimizePackageImports feature in Next.js to optimize your > bundle size by loading only the modules that you are actually using.
export default {
experimental: {
optimizePackageImports: ["@chakra-ui/react"],
},
}

Spinner を使っている箇所でエラーが発生する
import { FC } from "react";
import { Box, BoxProps, Spinner, SpinnerProps } from "@chakra-ui/react";
type LoaderProps = Pick<SpinnerProps, "size" | "color"> & BoxProps;
export const Loader: FC<LoaderProps> = ({
size = "md",
color = "blue.400",
...boxProps
}) => (
<Box {...boxProps}>
<Spinner size={size} color={color} />
</Box>
);
./node_modules/@chakra-ui/icons/dist/esm/Spinner.mjs
Attempted import error: 'forwardRef' is not exported from '@chakra-ui/react' (imported as 'forwardRef').
@chakra-ui/icons が対応しきれてないっぽい
Both
@chakra-ui/icons
andforwardRef
have been removed.
- Replace forwardRef with the react one
- Replace @chakra-ui/icons with a robust library like react-icons
cf. https://github.com/chakra-ui/chakra-ui/issues/8986#issuecomment-2435935656
cf

@chakra-ui/icons を削除する
$ npm uninstall @chakra-ui/icons
react-icons などから別のアイコンライブラリを選定して置き換える
IconButton の使い方が変わっているので対応する
-
icon={<Icon />}
プロパティが廃止されている -
variant
プロパティのlink
がなくなっている
import { IconButton } from "@chakra-ui/react";
const CloseButton = ({ onClose }) => {
return (
<IconButton
onClick={onClose}
aria-label="close timeline"
- icon={<CloseIcon />}
size="sm"
- variant="link"
+ variant="plain"
- />
+ >
+ <CloseIcon />
+ </IconButton>
);
}

<Checkbox>
が使えなくなってる
Checkbox コンポーネントを使っている箇所でクラッシュする
import { Checkbox } from "@/components/ui/checkbox"
@/components/ui/checkbox
からインポートしろとある
事前に snippet を生成する必要があった
cf. https://www.chakra-ui.com/docs/get-started/installation#add-snippets
$ npx @chakra-ui/cli snippet add
上記コマンドでスニペットを生成し、それを使う方針になっている
デフォルトでは @/components/ui
ディレクトリに生成せされる
別のディレクトリに snippet を生成する
すでに @/components/ui
ディレクトリを使用していると困る
--outdir
オプションを使うことで別のディレクトリに snippet を生成することができた
% npx @chakra-ui/cli snippet add --outdir ./src/components/chakraui
今回は @/components/chakraui
で呼び出せるようにした
snippet を生成すれば import 元を変更するだけで良い
- import { Checkbox } from "@@chakra-ui/react";
+ import { Checkbox } from "@/components/chakraui/checkbox";

onChange
イベントの currentTarge が label になる
v3 では Checkbox evt.currentTarget.value
が undefined
になっていた
import { FC, ReactNode } from "react";
import { Checkbox } from "@/components/chakraui/checkbox";
import { useDisplayInfoMutators } from './hooks/useDisplayInfo';
type MyCheckboxProps = {
id: string;
isChecked?: boolean;
label: ReactNode;
};
export const MyCheckbox: FC = ({ id, isChecked = false, label }) => {
consy { onChange } = useDisplayInfoMutators();
const handleToggle = (evt: ChangeEvent<HTMLInputElement>) => {
const id = evt.currentTarget.value; // -> undefined
const checked = evt.currentTarget.checked; // -> undefined
onChange(id, checked);
};
return (
<Checkbox
onChange={handleToggle}
value={id}
checked={isChecked}
>
{label}
</Checkbox>
);
}
Chakra UI v3 では event.currentTarget
が <label>
になるように変わっていた
event.target
にすれば <input>
が取得できる
export const MyCheckbox: FC = ({ id, isChecked = false, label }) => {
consy { onChange } = useDisplayInfoMutators();
const handleToggle = (evt: ChangeEvent<HTMLInputElement>) => {
- const id = evt.currentTarget.value; // -> undefined
+ const id = evt.target.value;
- const checked = evt.currentTarget.checked; // -> undefined
+ const checked = evt.target.checked;
onChange(id, checked);
};
return (
<Checkbox
onChange={handleToggle}
value={id}
checked={isChecked}
>
{label}
</Checkbox>
);
}
単純に check されているかどうかなら onCheckedChange を使えばOK
export const MyCheckbox: FC = ({ id, isChecked = false, label }) => {
consy { onChange } = useDisplayInfoMutators();
const handleToggle = (checked: boolean) => {
onChange(id, checked);
};
return (
<Checkbox
onCheckedChange={handleToggle}
value={id}
checked={isChecked}
>
{label}
</Checkbox>
);
}