Chakra UI(チャクラUI)は、React向けのUIコンポーネントライブラリです。ボタン・フォーム・ダイアログなどの部品と、padding="4"のようにpropsでスタイルを書く仕組みをまとめて提供します。ライセンスはMITで、商用でも無料で使えます。
2026年10月27日時点の最新版はv3.37.0(2026年8月28日公開)です。v3は2024年10月に出た全面改訂版で、インストール手順も書き方もv2と大きく違います。日本語で読める解説の多くは2022〜2024年に書かれたv2向けで、そのまま真似るとframer-motionを余計に入れたり、効かないpropsを書いたりします。この記事では特徴とメリット・デメリットを整理したうえで、v3の導入手順と基本の使い方を、手元で型チェックとレンダリングを通したコードで示します。
まとめ:Chakra UI v3の要点
- 最新版はv3.37.0。インストールは
npm i @chakra-ui/react @emotion/reactの2パッケージで、Node.js 20以上が必要。 - 強みはスタイルプロップの書きやすさと、Ark UIが担うキーボード操作・フォーカス管理。弱みはEmotionによる実行時のCSS生成と、v2時代の情報が多いこと。
- npmの版別ダウンロードでは、v3公開から2年たった今もv2系が46.0%を占める。ただしセキュリティ修正の対象は最新メジャーのv3だけなので、新規採用ならv3一択。
- v2からの移行は公式のcodemodで大半を自動変換できる。ただし
colorSchemeの残りは型チェックを通ってしまうので、変換後に文字列検索で洗い出す。 - ボタンを押したときに周りがずれるなら、
loadingTextによる幅の変化か、Dialogのスクロールロックによる固定ヘッダーのずれを確認する。
Chakra UIの特徴とメリット・デメリット
v3のChakra UIは、見た目と振る舞いを別々の層に任せています。開閉・フォーカス移動・キーボード操作といった振る舞いは、同じ開発チームのArk UI(v3.37.0の依存は@ark-ui/react 5.39.0)が担い、見た目はEmotionが実行時にCSSを生成して当てます。メリットとデメリットは、どちらもこの構成から出てきます。
メリット:propsで書けるスタイルとArk UIのアクセシビリティ
- スタイルをpropsで書ける:
<Box p="4" bg="gray.100">のように書くため、CSSファイルとコンポーネントを行き来しない。値はトークン(4=1rem)に乗るので、余白や色が画面ごとにばらつきにくい。 - キーボード操作を自前で書かなくてよい:ダイアログのフォーカス閉じ込め、メニューの矢印キー移動、Escキーでの閉じる操作はArk UI側に実装済み。aria属性を自分で書き足す場面は少ない。
- 特定のデザイン言語に縛られない:Material Designのような既定の見た目を前提にしていないので、独自ブランドの画面に合わせやすい。ライトとダークの切り替えもトークンで一か所にまとめられる。
デメリット:実行時のCSS生成とv2時代の情報の多さ
- CSSを実行時に生成する:公式のインストールページは「Today, Chakra UI uses Emotion at runtime」と明記し、Panda CSSに着想を得たゼロランタイム方式へは段階的に移る方針を示すにとどまっている。部品はクライアントコンポーネントとして動き、スタイル計算のコストもブラウザ側で払う。
- 検索で見つかる情報がv2中心:v2の
extendThemeやcolorSchemeを使ったコード例はv3では動かないか、動いても効かない。参照する記事やドキュメントの版を毎回確かめる手間がかかる。 - v2からの移行が重い:部品名・props名・テーマの書き方がまとめて変わり、codemodで変換しきれない箇所が残る(後述)。
ビルド時にCSSを生成する構成が必須の案件なら、同じチームが作ったPanda CSS(型付きスタイル生成の設定と採用判断)を先に検討してください。
v2とv3のダウンロード状況とサポート方針
「Chakra UIは今も使われているのか」は、npmの公開APIで版ごとのダウンロード数を見ると分かります。2026年10月19日〜25日の1週間で@chakra-ui/reactは約104万回ダウンロードされ、その内訳は次のとおりでした(npmの版別ダウンロード数APIで2026年10月27日に取得。期間を指定した集計APIでも同じ1,044,742回)。
| 系列 | 最新版 | 公開日 | 週間DLの割合 | 扱い |
|---|---|---|---|---|
| v3 | 3.37.0 | 2026-08-28 | 48.9% | 開発の本線 |
| v2 | 2.10.10 | 2026-06-04 | 46.0% | セキュリティ修正の対象外 |
| v1 | 1.8.9 | 2022-09-16 | 5.0% | 更新なし |
v3.0.0の公開は2024年10月22日ですが、2年たってもダウンロードのほぼ半分はv2系です。版単位では3.37.0が約16.8万回で最多、次いで2.10.9が約14.9万回でした。ダウンロード数にはCIでの再インストールや依存関係経由の取得も含まれるため、分かるのはv2系のパッケージ取得が今も多いことまでで、稼働中のアプリ数は判断できません。
v2は2026年6月にも2.10.10が出ています。ただしリポジトリのSECURITY.mdは「We release security updates for the latest major version.」としており、脆弱性の修正が約束されているのはv3だけです。v2のまま運用を続けるなら、依存パッケージの脆弱性通知を自分で追う前提になります。
Chakra UI v3のインストール手順
Next.jsとViteのどちらでも、最初の手順は共通です。v2の手順にあった@emotion/styledとframer-motionは、v3では不要になりました。手順の原文は公式のInstallationページにあります。
パッケージとスニペットの追加
# 1. 本体とEmotionを入れる(Node.js 20以上)
npm i @chakra-ui/react @emotion/react
# 2. Provider などのスニペットを components/ui に書き出す
npx @chakra-ui/cli snippet add
2つ目のコマンドは、ライブラリの部品をnpmの中ではなく自分のリポジトリにソースとして書き出します。既定で生成されるのはprovider.tsx・color-mode.tsx・toaster.tsx・tooltip.tsxの4ファイルです(CLI 3.37.0で確認)。ダークモードの切り替えはcolor-mode.tsxがnext-themesを使って実装しているので、中身を読めば挙動を追えます。
TypeScriptの場合は、生成された部品を@/components/ui/providerで読み込めるように、既存のTypeScript設定へパス設定を追加します。Viteの標準Reactテンプレートではtsconfig.app.jsonが対象です。以下はsrc配下にソースを置く構成なので、実際の配置に合わせてパスを調整してください。
{
"compilerOptions": {
"target": "ESNext",
"module": "ESNext",
"moduleResolution": "Bundler",
"skipLibCheck": true,
"paths": { "@/*": ["./src/*"] }
}
}
Next.js(App Router)のProvider設定
公式ドキュメントはNext.js 15と16への対応を明記しています。ルートレイアウトで全体をProviderで包み、<html>にsuppressHydrationWarningを付けます。付け忘れると、next-themesがクライアント側でクラスを書き換えるため、ハイドレーションの警告が出ます。
// app/layout.tsx
import { Provider } from "@/components/ui/provider"
export default function RootLayout({ children }: { children: React.ReactNode }) {
return (
<html lang="ja" suppressHydrationWarning>
<body>
<Provider>{children}</Provider>
</body>
</html>
)
}
// next.config.mjs:使った部品だけを読み込ませる
export default {
experimental: {
optimizePackageImports: ["@chakra-ui/react"],
},
}
Chakra UIの部品自体は内部でuseStateなどを使うクライアントコンポーネントですが、Server Componentのページから'use client'を書かずにそのまま使えます。chakra()ファクトリ、Chakraのフック、render propsを使う自作部品は、'use client'付きの別ファイルに分けます。App Routerの基本はNext.js 16系App Routerで最小アプリを動かす手順で確認できます。
Viteのパス解決設定
Viteではsrc/main.tsxでアプリをProviderで包み、tsconfigのパス設定をViteにも伝えます。Vite 8以降はresolve.tsconfigPaths: trueの1行で済み、Vite 7以下はvite-tsconfig-pathsプラグインを入れます。この設定が無いと@/components/ui/providerの読み込みで失敗します。
// vite.config.ts(Vite 8以降)
import react from "@vitejs/plugin-react"
import { defineConfig } from "vite"
export default defineConfig({
plugins: [react()],
resolve: { tsconfigPaths: true },
})
基本の使い方:スタイルプロップと組み立て式コンポーネント
Chakra UIの書き方は2種類だけ覚えれば足ります。単純な要素はpropsでスタイルを指定し、Tableやダイアログのような複合部品はTable.Root・Table.Rowのように部品を組み立てます。
レスポンシブ指定とuseBreakpointValue
ブレークポイントはモバイルファーストで、base(0px)・sm(30rem=約480px)・md(48rem=約768px)・lg(62rem=約992px)・xl(80rem)・2xl(96rem)の6段階です。propsにオブジェクトを渡すと、その幅以上で値が切り替わります。
"use client"
import { Stack, Text, useBreakpointValue } from "@chakra-ui/react"
export function Responsive() {
// JS側で値を分けたいときだけ使う(見た目の切り替えはpropsで足りる)
const label = useBreakpointValue({ base: "SP", md: "タブレット", lg: "PC" })
return (
<Stack direction={{ base: "column", md: "row" }} gap="4">
<Text fontSize={{ base: "sm", lg: "md" }}>表示中:{label}</Text>
<Text hideBelow="md">md未満では非表示</Text>
</Stack>
)
}
見た目の切り替えは、propsのオブジェクト指定で済ませるのが基本です。useBreakpointValueは画面幅が境界をまたぐたびにコンポーネントを再レンダリングさせるので、表示する部品そのものを差し替えたいときに限って使います。v3ではmdToXl(mdからxlの間だけ)やlgOnlyのような範囲指定も書けます。
Tableの書き方(v3の組み立て式)
v2のThead・Tr・Tdは、v3でTable.Header・Table.Row・Table.Cellに変わりました。横スクロールの枠はTableContainerからTable.ScrollAreaへ、数値列の右寄せはisNumericからtextAlign="end"へ置き換わっています。
import { Table } from "@chakra-ui/react"
const users = [
{ id: 1, name: "佐藤", role: "管理者", logins: 128 },
{ id: 2, name: "鈴木", role: "閲覧者", logins: 42 },
]
export function UserTable() {
return (
<Table.ScrollArea borderWidth="1px" maxW="full">
<Table.Root size="sm" striped>
<Table.Header>
<Table.Row>
<Table.ColumnHeader>名前</Table.ColumnHeader>
<Table.ColumnHeader>権限</Table.ColumnHeader>
<Table.ColumnHeader textAlign="end">ログイン回数</Table.ColumnHeader>
</Table.Row>
</Table.Header>
<Table.Body>
{users.map((u) => (
<Table.Row key={u.id}>
<Table.Cell>{u.name}</Table.Cell>
<Table.Cell>{u.role}</Table.Cell>
<Table.Cell textAlign="end">{u.logins}</Table.Cell>
</Table.Row>
))}
</Table.Body>
</Table.Root>
</Table.ScrollArea>
)
}
FieldとDialogの基本構成
入力欄のラベル・必須マーク・エラー文はFieldでまとめます。v2のisRequired・isInvalidは、v3ではrequired・invalidです。ダイアログはv2のModalがDialogに改名され、削除確認のような用途はrole="alertdialog"を付けて作ります。以下は画面構成の例で、メールアドレスの検証と削除処理は含みません。エラー文を表示するには、検証結果に応じてField.Rootへinvalidを渡してください。
import { Button, CloseButton, Dialog, Field, Input, Portal, Stack } from "@chakra-ui/react"
export function DeleteAccount() {
return (
<Stack gap="4">
<Field.Root required>
<Field.Label>
確認用メールアドレス <Field.RequiredIndicator />
</Field.Label>
<Input type="email" placeholder="[email protected]" />
<Field.ErrorText>メールアドレスの形式が正しくありません</Field.ErrorText>
</Field.Root>
<Dialog.Root role="alertdialog">
<Dialog.Trigger asChild>
<Button colorPalette="red" variant="outline">アカウントを削除</Button>
</Dialog.Trigger>
<Portal>
<Dialog.Backdrop />
<Dialog.Positioner>
<Dialog.Content>
<Dialog.Header>
<Dialog.Title>本当に削除しますか?</Dialog.Title>
</Dialog.Header>
<Dialog.Body>この操作は取り消せません。</Dialog.Body>
<Dialog.Footer>
<Dialog.ActionTrigger asChild>
<Button variant="outline">キャンセル</Button>
</Dialog.ActionTrigger>
<Button colorPalette="red">削除する</Button>
</Dialog.Footer>
<Dialog.CloseTrigger asChild>
<CloseButton size="sm" />
</Dialog.CloseTrigger>
</Dialog.Content>
</Dialog.Positioner>
</Portal>
</Dialog.Root>
</Stack>
)
}
画面の端から出るパネルはDrawerで、書き方はDialogとほぼ同じです。placementの指定やv2からの書き換えはChakra UI Drawerの使い方(v3の実装とv2からの移行)にまとめています。
テーマのカスタマイズ:createSystemとトークン
v3のテーマは、色やフォントをトークンとして定義し、createSystemで既定の設定に重ねます。v2のextendThemeは廃止され、値はすべて{ value: ... }の形で書きます。ライトとダークで切り替えたい色はセマンティックトークンに置きます。
// src/theme.ts
import { createSystem, defaultConfig, defineConfig } from "@chakra-ui/react"
const config = defineConfig({
theme: {
tokens: {
colors: {
brand: {
500: { value: "#1a73e8" },
600: { value: "#1558b0" },
},
},
fonts: {
body: { value: "'Noto Sans JP', sans-serif" },
},
},
semanticTokens: {
colors: {
"brand.solid": {
value: { _light: "{colors.brand.500}", _dark: "{colors.brand.600}" },
},
},
},
},
})
export const system = createSystem(defaultConfig, config)
作ったsystemは、スニペットのprovider.tsxにあるdefaultSystemと差し替えます。v2でthemeだったChakraProviderのpropsは、v3ではvalueです。
TypeScriptで独自トークンの補完を効かせるには、npx @chakra-ui/cli typegen src/theme.tsで型を生成します(CLIはNode.js 20.6.0以上)。公式はpostinstallかprepareのどちらか一方に登録して、CIでも毎回生成する運用を勧めています。生成し忘れると、追加したbrand.solidが補完に出ません。未定義のトークン名を型エラーにするには、型生成に加えてstrictTokens: trueの設定が必要です。
v2からv3への移行:主な書き換え対応表
移行はNode.js 22以上の環境で公式のcodemodから始めます。npx @chakra-ui/codemod upgradeで、コンポーネント名・props名・importの書き換えをまとめて実行します(--dryで事前確認できます)。全項目は公式の移行ガイドにあり、変換後に手で確かめたい主な項目は次のとおりです。
| v2 | v3 |
|---|---|
| extendTheme | createSystem+defaultConfig |
| ChakraProvider theme= | ChakraProvider value= |
| colorScheme | colorPalette |
| isDisabled・isOpen・isInvalid | disabled・open・invalid |
| Stack spacing | Stack gap |
| Modal | Dialog |
| AlertDialog | Dialog(role=alertdialog) |
| blockScrollOnMount | preventScroll |
| useColorMode・useColorModeValue | スニペットのcolor-mode.tsx |
| @chakra-ui/icons | react-iconsやlucide-react |
| @chakra-ui/next-js | Link・BoxのasChild |
| framer-motion・@emotion/styled | 不要(アンインストール) |
カラーモードの関数は本体から消えましたが、スニペットのcolor-mode.tsxが同名のuseColorModeとuseColorModeValueを提供します。import元を@/components/ui/color-modeに変えれば、呼び出し側のコードはほぼそのまま使えます。
codemod後のcolorScheme残存と型チェックの限界
v3への移行で最も見落としやすいのがcolorSchemeです。isDisabledやspacingをv3のコードに残すと、TypeScriptは未対応のpropsとして型エラーを報告します。ところがcolorSchemeは止まりません。CSSにもともとcolor-schemeというプロパティがあり、v3のスタイルプロップとして受け付けられてしまうからです。
検証環境はNode.js 26.5.0、React 19、TypeScript 5、@chakra-ui/react 3.37.0です。型チェックとReactDOMServerによるSSRで、次の結果を確認しています。
<Button colorScheme="blue">はtscを通過する。- サーバー側でレンダリングすると、出力されるCSSは
color-scheme:blueで、ボタンは既定のグレーのまま。blueパレットへの参照は0件(colorPalette="blue"では19件)。 - codemodの変換は、JSXに直接書いた
colorScheme="teal"はcolorPaletteに直すが、const primary = { colorScheme: "blue" }を<Button {...primary}>で渡した書き方は変換しない。
つまり、ボタンの色をオブジェクトにまとめて共通化していたプロジェクトほど、変換後もビルドが通ったまま色だけ抜け落ちます。codemodを実行したら、型チェックに頼らず文字列で探してください。
# codemod後に残ったv2のpropsを洗い出す
grep -rn -E "colorScheme|isDisabled|isLoading|isOpen|spacing=" src
JavaScriptのプロジェクトではisDisabledも通常は型チェックされません。文字列検索に加え、TypeScriptのcheckJsによる検査や、操作テストでも移行漏れを確認できます。
ボタンを押すと周りの要素がずれる原因と対処
v3でボタンを押した瞬間にレイアウトが動く場合、確認候補として、ボタン内の表示切り替えとDialogのスクロールロックがあります。いずれも3.37.0のソースとSSRの出力で確かめました。
loadingTextによるボタン幅の変化と対処
Buttonのloadingには2通りの表示があります。loadingだけを渡すと、元の文字をvisibility: hiddenで隠したまま残し、その上にスピナーを重ねます。文字の分だけ幅が保たれるので、隣の要素は動きません。一方loadingText="保存中..."を付けると、元の文字を描画せずスピナーと新しい文字に差し替えるため、文字列・スピナー・間隔の合計幅によってボタン幅が変わり、横に並んだ要素が動く場合があります。
押したあとも配置を固定したいなら、公式のButtonドキュメントの「幅を保ったまま切り替える」例と同じく、loadingTextを外します。どうしても文言を出したい場合は、minWで長い方の文言が収まる幅を確保します。
"use client"
import { Button } from "@chakra-ui/react"
import { useState } from "react"
export function SaveButton({ onSave }: { onSave: () => Promise<void> }) {
const [saving, setSaving] = useState(false)
async function handleClick() {
setSaving(true)
try {
await onSave()
} finally {
setSaving(false)
}
}
// loadingText を付けないと、文字を隠したまま幅を保ってスピナーを重ねる
return (
<Button loading={saving} onClick={handleClick}>
保存する
</Button>
)
}
loading中のボタンにはdisabledが自動で付くため、処理中の同じボタンの再クリックを抑止できます。ただし、別の送信経路や通信の再試行も含む重複処理の防止は、アプリケーション側で設計する必要があります。
Dialog表示時の固定ヘッダーの横ずれと補正
ボタンでDialogを開いた瞬間に、スクロールバーの表示方式やレイアウトによっては、画面上部の固定ヘッダーが横にずれる場合があります。DialogはpreventScrollが既定でtrueで、開いている間は背後のページをスクロールさせないよう、スクロール要素にoverflow: hiddenを当ててスクロールバーを消します。このとき本文がずれないようにスクロールバーの幅だけpaddingを足しますが、position: fixedの要素にはその補正が届きません。
補正に使う値は、ロック中に<html>へ--scrollbar-widthとして書き込まれ、<body>にはdata-scroll-lock属性が付きます(Ark UIが使う@zag-js/remove-scroll 1.43.3のソースで確認)。以下は、右側に通常のスクロールバーがあり、scrollbar-gutterを指定していない左から右へのレイアウト向けです。この条件で固定ヘッダーがずれる場合に限り、ロック中の余白を補正します。
import { Box, Flex } from "@chakra-ui/react"
export function AppHeader({ children }: { children: React.ReactNode }) {
return (
<Box
as="header"
position="fixed"
top="0"
insetInline="0"
css={{
// Dialog のスクロールロック中だけ、消えたスクロールバーの幅を足す
"body[data-scroll-lock] &": { paddingInlineEnd: "var(--scrollbar-width)" },
}}
>
<Flex justify="space-between" px="4" h="14" align="center">
{children}
</Flex>
</Box>
)
}
スクロールバーの幅は「ウィンドウ幅-表示領域の幅」で測られるため、スクロールバーが重ねて表示されるmacOSの既定設定では0になり、この現象は再現しません。Macだけで動作確認していると見逃します。なお<html>か<body>にscrollbar-gutter: stableを指定している場合、ライブラリ側のpadding補正は行われませんが、data-scroll-lock属性と--scrollbar-widthは設定されます。その構成で上のCSSを残すと、ずれていないヘッダーに余白を足してしまうので外してください。
Chakra UIを選ぶ場面・選ばない場面
ReactのUIライブラリは、部品を丸ごと提供するものと、スタイルの書き方だけを提供するものに分かれます。Chakra UIは前者の中で、Material Designのような特定のデザイン言語に縛られない点が特徴です。
| 候補 | スタイルの仕組み | 部品の持ち方 | 見た目の前提 |
|---|---|---|---|
| Chakra UI v3 | Emotion(実行時) | npm+スニペット | 独自デザイン向け |
| Material UI | Emotion(実行時) | npm | Material Design |
| shadcn/ui | Tailwind CSS(ビルド時) | ソースをコピー | 独自デザイン向け |
| Panda CSS | ビルド時に生成 | 部品なし | なし |
社内の管理画面や業務システムのように、独自のデザインで画面数が多く、アクセシビリティも確保したい案件ではChakra UIが向きます。トークンとセマンティックトークンでブランド色とダークモードを一か所に集められ、ダイアログやメニューのキーボード操作をArk UIに任せられるからです。画面設計から外部に相談する場合は、UI/UXデザインの支援も検討材料になります。
選ばないほうがよいのは次の場面です。
- Material Designに準拠する必要がある:最初からMaterial Designの部品を持つMaterial UI(v9系の導入とテーマ設定)のほうが手戻りが少ない。
- チームがTailwind CSSで統一している:Chakraのスタイルプロップとユーティリティクラスが混在すると、同じ余白を2通りで書くことになる。部品のソースを手元に置くshadcn/uiが合う。
- 実行時のCSS生成を避けたい:ゼロランタイムへの移行はまだ方針の段階なので、現時点でビルド時生成が必須ならPanda CSSか、振る舞いだけを提供するRadix UI Primitivesにスタイルを自前で当てる構成を選ぶ。
propsでスタイルを当てる書き味はそのままに、公式の日本語ドキュメントが欲しい場合は、Chakra UIなどから着想を得たと公式READMEに明記しているYamada UI(@yamada-ui/react v2の導入とテーマ設計)も候補になります。
よくある質問
Chakra UIは無料?商用利用できる?
本体(@chakra-ui/react)はMITライセンスで、商用でも無料で使えます。有料なのは、CLIのblocksコマンドで追加できる「Chakra UI Pro」のブロック集で、公式販売ページの表示は、個人向けが買い切り(One-time Purchase)299ドル、チーム向けが899ドルです(2026年10月27日確認。定価349ドル・999ドルからの割引表示のため、購入時に再確認してください)。
Chakra UIの読み方は?
「チャクラ・ユーアイ」と読み、日本語の記事では「チャクラUI」とも表記されます。英語では綴りを詰めた「chakraui」や、パッケージ名の「@chakra-ui/react」で検索されることもあります。
これから使うならv2とv3のどちら?
v3です。v2は2026年6月にも2.10.10が公開されましたが、セキュリティ修正の対象は最新メジャーのv3だけとリポジトリに明記されています。v2の解説記事のコードはv3では動かないものが多いため、参照するドキュメントの版も確かめてください。
Chakra UI v4はいつ出る?
2026年10月27日時点で、npmのdist-tagsにv4の版はなく、公式が示している今後の方針はスタイル層を段階的にゼロランタイムへ移すことだけです。公開日は発表されていないので、新規開発はv3で始めて問題ありません。
Chakra UIはServer Componentsで使える?
使えます。Chakraの部品はクライアントコンポーネントですが、Server Componentのページから'use client'を書かずに配置できます。chakra()ファクトリ、Chakraのフック、render propsを使う自作部品は、'use client'付きの別ファイルに置く必要があります。