---
title: "Chakra UI Drawerの使い方｜v3（3.37）の実装とv2からの移行・placement設定"
url: "https://www.issoh.co.jp/tech/details/4398/"
published: 2024-12-04
updated: 2026-11-03
categories: ["React"]
publisher: "株式会社一創"
---

# Chakra UI Drawerの使い方｜v3（3.37）の実装とv2からの移行・placement設定

Chakra UIのDrawerは、v3で書き方が根本から変わりました。v2の `isOpen` と `DrawerOverlay` を使ったコードは、2026年8月28日公開の最新版 3.37.0 でも型エラーになって動きません。この記事では 3.37.0 の型定義とスロットレシピ、変更履歴から確認できる事実をもとに、v3の最小実装、v2からの移行対応表、placementとsizeの指定値、閉じると入力が消える問題までを整理します。

## まとめ：Chakra UI v3 Drawer実装の要点

v3のDrawerは `Drawer.Root` を頂点とする名前空間コンポーネントで、開閉は `open` と `onOpenChange` で制御します。

| 論点            | v3（3.37.0）での結論                       |
| ------------- | ------------------------------------ |
| 開閉プロパティ       | open と onOpenChange（引数はオブジェクト）       |
| placement     | start / end / top / bottom（既定 end）   |
| size          | xs / sm / md / lg / xl / full（既定 xs） |
| オーバーレイ・閉じるボタン | Drawer.Backdrop・Drawer.CloseTrigger  |
| 閉じたときの中身      | 既定で破棄（unmountOnExit: true）           |
| スワイプで閉じる      | 非対応（Ark UI の Drawer を使う）             |

移行で最初に潰すのは `placement="right"` です。v2の既定値 right は v3では型が受け付けません。もう一つ見落としやすいのが、閉じるとDrawerの中身がアンマウントされる既定動作で、Drawer内のコンポーネントだけが持っていた入力値は閉じた時点で消えます。

## Chakra UIにおけるDrawerとDialogの使い分け

### Drawerを選ぶ条件とDialogへ倒す条件

ドロワーは画面の端から滑り込むパネルで、元の画面を残したまま補助的な操作面を重ねるUIです。基準は単純で、**元の画面の文脈を保ちたいならDrawer、いま答えないと先へ進めないならDialog**。削除確認や決済確定は画面中央のDialog、背後の一覧を見ながら条件を変える絞り込みはDrawerが向きます。UI用語としての定義と一般的な選定基準は[ドロワーUIとモーダル・ダイアログの違いと使い分け](/tech/details/7075/)で扱っています。

実装上の土台は同じです。3.37.0 の `drawer.js` は `@ark-ui/react/dialog` の `Dialog` をimportしており、`useDrawer` も Ark UI の `useDialog` の再エクスポートです。違うのは画面端へ寄せてスライドさせるレシピだけです。

### Drawerを使うべきでない画面

**入力項目が多いフォームをDrawerに詰め込む設計は避けてください。**既定サイズ xs の content は maxW が 20rem（320px）しかなく、長いラベルや複数の入力欄を横に並べるフォームには狭すぎます。後述のとおり閉じると入力が消える既定動作もあり、size を lg まで上げるくらいなら専用ページに切り出したほうが、戻る操作もURL共有も素直になります。Drawerの中でさらにDrawerを開く多重構造もフォーカス管理が崩れやすい形です。画面全体の構造から考えるなら[業務システムの画面デザインとUI設計パターン](/tech/details/15325/)が判断材料になります。

## v3のDrawer構成要素と最小実装コード

### Drawer.RootからCloseTriggerまでの部品一覧

3.37.0 の `namespace.d.ts` がエクスポートする部品は、Root / RootProvider / RootPropsProvider / Trigger / Positioner / Content / Backdrop / Body / Header / Footer / Title / Description / CloseTrigger / ActionTrigger / Context の15個です。`Drawer` 名前空間からドット記法で参照します。次のコードは、アプリのルートに `<ChakraProvider value={defaultSystem}>` を置いている前提です。置いていないと、3.37.0 では「ChakraProvider で囲み忘れている」という趣旨の例外が出て描画が止まります。

```
import { Button, CloseButton, Drawer, Portal } from "@chakra-ui/react"
import { useState } from "react"

export function SettingsDrawer() {
  const [open, setOpen] = useState(false)
  return (
    <Drawer.Root open={open} onOpenChange={(e) => setOpen(e.open)} placement="end" size="md">
      <Drawer.Trigger asChild>
        <Button variant="outline">設定を開く</Button>
      </Drawer.Trigger>
      <Portal>
        <Drawer.Backdrop />
        <Drawer.Positioner>
          <Drawer.Content>
            <Drawer.Header>
              <Drawer.Title>表示設定</Drawer.Title>
            </Drawer.Header>
            <Drawer.Body>
              <p>本文をここに置きます。</p>
            </Drawer.Body>
            <Drawer.Footer>
              <Drawer.ActionTrigger asChild>
                <Button variant="outline">キャンセル</Button>
              </Drawer.ActionTrigger>
              <Button>保存</Button>
            </Drawer.Footer>
            <Drawer.CloseTrigger asChild>
              <CloseButton size="sm" />
            </Drawer.CloseTrigger>
          </Drawer.Content>
        </Drawer.Positioner>
      </Portal>
    </Drawer.Root>
  )
}
```

`Drawer.Trigger` に `asChild` を付けると、自前のボタンへ開閉イベントとARIA属性を引き渡せます。`Drawer.ActionTrigger` はフッターのキャンセル用で、押すとドロワーが閉じます。3.36.1 以前はこのActionTriggerに `type="button"` が付かず、`<form>` の中に置くと押した瞬間にフォームが送信されていました。渡した `onClick` が無視される不具合もあり、どちらも[Chakra UIの変更履歴](https://github.com/chakra-ui/chakra-ui/blob/main/packages/react/CHANGELOG.md)によれば3.37.0で修正されています。Drawer内にフォームを置くなら3.37.0へ上げるのが先です。

### Positionerが担う配置とPortalを挟む理由

v2に無かった `Drawer.Positioner` は配置を受け持つ層です。positioner は `position: fixed` で幅 100vw・高さ 100dvh を占め、placement に応じて `justifyContent` と `alignItems` を切り替えて content を端へ寄せます。

`Portal` で囲むのは、祖先の `transform` や `overflow: hidden` から切り離すためです。祖先に `transform` があると新しいスタッキングコンテキストができ、Drawer の z-index はその中だけで比べられます。祖先自体の重なり順が固定ヘッダーより低ければ、Drawer の z-index をいくら上げてもヘッダーの下に隠れます。

## v2からv3への移行対応表と実際に出る型エラー

### 部品名・プロパティの対応表

v2（2.10.10）とv3（3.37.0）の型定義を突き合わせた対応です。公式の[v3移行ガイド](https://chakra-ui.com/docs/get-started/migration)も同じ置き換えを示しています。

| v2（2.10.10）        | v3（3.37.0）              | 備考               |
| ------------------ | ----------------------- | ---------------- |
| Drawer             | Drawer.Root             | Drawerは名前空間      |
| isOpen / onClose   | open / onOpenChange     | 引数はオブジェクト        |
| DrawerOverlay      | Drawer.Backdrop         | 名称変更             |
| DrawerCloseButton  | Drawer.CloseTrigger     | ボタンは自前で置く        |
| （なし）               | Drawer.Positioner       | 配置を担当            |
| DrawerContent ほか3つ | Drawer.Content ほか       | フラット名も残存         |
| placement=”right”  | placement=”end”         | left / right は削除 |
| initialFocusRef    | initialFocusEl          | ref でなく関数        |
| isFullHeight       | Content に height=”100%” | 移行ガイドの指定         |

注意したいのは DrawerContent / DrawerHeader / DrawerBody / DrawerFooter の4つです。v3にもフラットな名前で残っているため、一部のimportだけが通ってしまいます。

### v2コードを3.37.0で型検査したときのエラー5件

次のv2記法を、React 19.3.1・TypeScript 5.9.3・@chakra-ui/react 3.37.0 の構成で `tsc` にかけました。

```
import { Drawer, DrawerOverlay, DrawerContent, DrawerCloseButton,
         DrawerHeader, DrawerBody, useDisclosure } from "@chakra-ui/react"

export function OldDrawer() {
  const { isOpen, onOpen, onClose } = useDisclosure()
  return (
    <Drawer isOpen={isOpen} placement="right" onClose={onClose}>
      <DrawerOverlay />
      <DrawerContent>
        <DrawerCloseButton />
        <DrawerHeader>メニュー</DrawerHeader>
        <DrawerBody>本文</DrawerBody>
      </DrawerContent>
    </Drawer>
  )
}
```

出力は5件です（ファイル名・行番号・パスは省略）。

```
error TS2305: Module '"@chakra-ui/react"' has no exported member 'DrawerOverlay'.
error TS2305: Module '"@chakra-ui/react"' has no exported member 'DrawerCloseButton'.
error TS2339: Property 'isOpen' does not exist on type '{ open: boolean; onOpen: () => void;
       onClose: () => void; onToggle: () => void; setOpen: Dispatch<SetStateAction<boolean>>; }'.
error TS2604: JSX element type 'Drawer' does not have any construct or call signatures.
error TS2786: 'Drawer' cannot be used as a JSX component.
  Its type 'typeof import(".../components/drawer/namespace")' is not a valid JSX element type.
```

読み解きどころは TS2604 と TS2786 です。v3の `Drawer` は関数コンポーネントではなく名前空間オブジェクトなので、型の問題に見えても実体は書き方の変更です。逆に DrawerContent 以下のimportは素通りします。**型エラーの件数で移行の進み具合を測ると、通ってしまった箇所を見落とします。**`Drawer` を含むimportを全件洗い出してドット記法へ置き換えるのが確実です。Chakra UI全体の変更点は[Chakra UI v3の使い方・インストール手順とv2移行の注意点](/tech/details/3059/)にまとめています。

## openとonOpenChangeによる開閉制御とuseDisclosure

### useDisclosureの戻り値5つと最小の開閉実装

useDisclosure はv3でも残っていますが、3.37.0 の `use-disclosure.d.ts` が返すのは `open` / `onOpen` / `onClose` / `onToggle` / `setOpen` の5つです。v2の `isOpen` は無くなりました。

```
import { Button, Drawer, Portal, useDisclosure } from "@chakra-ui/react"

export function CartDrawer() {
  const { open, onOpen, onClose, onToggle } = useDisclosure()
  return (
    <>
      <Button onClick={onOpen}>カートを見る</Button>
      <Button onClick={onToggle}>切り替え</Button>
      <Drawer.Root open={open} onOpenChange={(e) => (e.open ? onOpen() : onClose())}>
        <Portal>
          <Drawer.Backdrop />
          <Drawer.Positioner>
            <Drawer.Content>
              <Drawer.Header>
                <Drawer.Title>カート</Drawer.Title>
              </Drawer.Header>
              <Drawer.Body>カートの中身</Drawer.Body>
            </Drawer.Content>
          </Drawer.Positioner>
        </Portal>
      </Drawer.Root>
    </>
  )
}
```

`onOpenChange` が受け取るのは真偽値ではなく `{ open: boolean }` を持つオブジェクトです。v2の感覚で `onOpenChange={setOpen}` と書くと、TypeScriptでは次のエラーで止まります。JavaScriptでは素通りして状態にオブジェクトが入り、「閉じなくなる」不具合になります。

```
error TS2322: Type 'Dispatch<SetStateAction<boolean>>' is not assignable to type
  '(details: OpenChangeDetails) => void'.
```

### 非制御（defaultOpen）と制御の使い分け

開閉状態を親やURLと同期させないなら、stateは不要です。`Drawer.Trigger` と `Drawer.CloseTrigger` だけで開閉は完結し、初期表示で開きたいときは `defaultOpen` を渡します。制御に切り替えるのは、開閉を外部の状態や処理と同期させたいときです。開閉をクエリパラメータへ載せる、未保存の入力を理由に閉じる操作を止める、保存処理の完了を待って閉じる、といった場面が当たります。

### Triggerの自作コンポーネント化とページ遷移で閉じない問題

開くボタンを自前のコンポーネントへ切り出した途端に反応しなくなるのは、`asChild` が子要素へpropsを引き渡す仕組みだからです。**子コンポーネントがpropsを下のDOM要素へ渡していないと、クリックハンドラもARIA属性も届きません。**propsを受け取って展開する形にします。

```
function MyTriggerButton(props: React.ComponentProps<typeof Button>) {
  return <Button {...props} />
}
```

ドロワー内のリンクでページを移動しても開いたままになる問題は、Drawerがルーターと連動しないことが原因です。`drawer.js` のimportは React と Ark UI の Dialog、内部のスタイル関数だけです。ナビゲーション用のドロワーでは、パスの変化を監視して `setOpen(false)` を呼ぶか、リンクを `Drawer.ActionTrigger` で包んで押下時に閉じます。

## placementとsizeの指定値・既定値と実寸

### placementの4値とRTLで左右が入れ替わる理由

placement は start / end / top / bottom の4値で、既定は end です。省略時の見た目はv2と同じ右出しですが、`placement="right"` と書くと次のエラーになります。

```
error TS2322: Type '"right"' is not assignable to
  type 'ConditionalValue<"start" | "end" | "top" | "bottom" | undefined>'.
```

left / right が消えたのは、書字方向に追従させるためです。レシピの start は通常 `slide-from-left-full`、`_rtl` 条件下では `slide-from-right-full` のアニメーションを使います。多言語対応の予定が無ければ、start を左、end を右と読み替えれば足ります。

### サイズごとのmaxW上限とfullの100dvh

size は6値で既定は xs です。レシピが content に設定する maxW を、3.37.0 の `tokens/sizes.js` の値に展開すると次のとおりです。maxW は幅の上限なので、画面がそれより狭ければ画面幅に収まります。px はルート文字サイズ16pxの場合の換算です。

| size   | 参照トークン | content の maxW（上限） |
| ------ | ------ | ------------------ |
| xs（既定） | xs     | 20rem（320px）       |
| sm     | md     | 28rem（448px）       |
| md     | lg     | 32rem（512px）       |
| lg     | 2xl    | 42rem（672px）       |
| xl     | 4xl    | 56rem（896px）       |
| full   | －      | 100vw・高さ100dvh     |

size の名前と参照トークンは一致しません。size=”sm” は sm トークン（24rem）ではなく md（28rem）を使います。上限は xl で、`size="2xl"` は TS2322 で止まります。

### contained と Positioner の padding で画面端から浮かせる指定

真偽値の `contained` を付けると、positioner に padding 4、content に `l3` の角丸が入り、画面端から浮いたパネルになります。余白の量を自分で決めたいなら、[公式のDrawerドキュメント](https://chakra-ui.com/docs/components/drawer)にあるとおり `Drawer.Positioner` に `padding` を直接渡し、content に `rounded` を付けます。

### スマホは下・PCは右に出すレスポンシブ指定

placement と size はブレークポイントごとのオブジェクトで渡せます。スマホでは下から全幅、md 以上では右から出す絞り込みパネルは次のとおりです。

```
import { Button, Drawer, Portal } from "@chakra-ui/react"

export function FilterDrawer() {
  return (
    <Drawer.Root placement={{ base: "bottom", md: "end" }} size={{ base: "full", md: "sm" }}>
      <Drawer.Trigger asChild>
        <Button variant="outline">絞り込み</Button>
      </Drawer.Trigger>
      <Portal>
        <Drawer.Backdrop />
        <Drawer.Positioner>
          <Drawer.Content roundedTop={{ base: "l3", md: "none" }}>
            <Drawer.Header>
              <Drawer.Title>絞り込み条件</Drawer.Title>
            </Drawer.Header>
            <Drawer.Body>条件の一覧</Drawer.Body>
          </Drawer.Content>
        </Drawer.Positioner>
      </Portal>
    </Drawer.Root>
  )
}
```

top / bottom のときレシピは content の maxW を 100% で上書きするので、下出しでは size の幅指定が効きません。角丸も下出しのときだけ上側に付けます。ブレークポイントの切り方は[メディアクエリとブレークポイント設計の実装手順](/tech/details/15329/)が使えます。

## モバイル表示で崩れる原因と3.37.0での扱い

### 100vhと100dvhの違いによる下部の見切れ

スマートフォンで全画面ドロワーの下部が隠れるのは、v2時代の定番のつまずきでした。v2の `isFullHeight` は型定義のコメントで100vhを占めると説明されており、100vh はアドレスバーが隠れた状態の高さなので表示領域からはみ出します。3.37.0 のレシピは backdrop・positioner・content のいずれも、アドレスバーの伸縮に追従する `100dvh` を使います。content の `maxH` を `100vh` で上書きしないでください。

### 本文だけをスクロールさせるbodyスロットと背景スクロールのロック

レシピの base では body スロットに `overflow: auto` と `flex: 1` が入っており、ヘッダーとフッターを固定したまま本文だけが縦にスクロールします。追加のCSSは要りません。背景のスクロールは `preventScroll`（既定 true）が止めますが、3.36.1 以前は `<html>` 側がスクロールするレイアウトでロックが効かず、背後のページが動いていました。3.37.0の変更履歴に修正が載っています。

## 初期フォーカス・非モーダル・カスタムコンテナの指定

### 開いた瞬間のフォーカス先とdata-autofocus

開いたときのフォーカス先は、`initialFocusEl` → `data-autofocus` の付いた要素 → `data-no-autofocus` の付いていない最初のフォーカス可能要素 → content 本体、の順に決まります。`data-autofocus` と `data-no-autofocus` は3.37.0で追加された属性で、ref を作らずに指定できます。右上の閉じるボタンに先にフォーカスが当たって検索欄に入力できない、という定番の不満は次の2属性で解消します。

```
<Drawer.Content>
  <Drawer.CloseTrigger asChild data-no-autofocus>
    <CloseButton size="sm" />
  </Drawer.CloseTrigger>
  <Drawer.Body>
    <Field.Root>
      <Field.Label>キーワード</Field.Label>
      <Input placeholder="例：請求書" data-autofocus />
    </Field.Root>
  </Drawer.Body>
</Drawer.Content>
```

### 非モーダルのDrawerとカスタムコンテナ

背後の画面を操作できるまま開いておきたいなら `modal={false}` を渡します。jsdom上で描画すると、positioner に `pointer-events: none`、content に `pointer-events: auto` が自動で付き、body のスクロールロックも掛かりませんでした。公式ドキュメントは positioner への `pointerEvents="none"` の明示も勧めていますが、3.37.0 が使う @zag-js/dialog 1.43.3 は同じ値を自分で付けます。外側をクリックしても閉じないよう `closeOnInteractOutside={false}` も併用します。

```
import { Button, CloseButton, Drawer, Portal } from "@chakra-ui/react"

export function MemoDrawer() {
  return (
    <Drawer.Root modal={false} closeOnInteractOutside={false}>
      <Drawer.Trigger asChild>
        <Button variant="outline">メモを開く</Button>
      </Drawer.Trigger>
      <Portal>
        <Drawer.Positioner>
          <Drawer.Content>
            <Drawer.Header>
              <Drawer.Title>メモ</Drawer.Title>
            </Drawer.Header>
            <Drawer.Body>背後の一覧も操作できます</Drawer.Body>
            <Drawer.CloseTrigger asChild>
              <CloseButton size="sm" />
            </Drawer.CloseTrigger>
          </Drawer.Content>
        </Drawer.Positioner>
      </Portal>
    </Drawer.Root>
  )
}
```

ただし公式はアクセシビリティ上の理由で非モーダルを推奨していません。フォーカスが背後へ移れるため、見出しや名前付け、閉じた後のフォーカスの戻し先まで設計しないと、スクリーンリーダーの利用者が現在位置を把握しにくくなります。常時表示の補助パネルなら、Drawerではなく通常のレイアウト内のサイドバーとして組むほうが筋がよい場面です。画面全体ではなく特定の領域の中に出したいときは、`<Portal container={ref}>` で描画先を差し替え、Backdrop と Positioner に `pos="absolute"` と `boxSize="full"` を指定します。

## 閉じると入力が消える：unmountOnExitとhideMode

3.37.0 の `drawer.js` は既定値として `unmountOnExit: true` と `lazyMount: true` を設定しています。初めて開くまで中身を描画せず、閉じたら中身を破棄する動きです。Drawer内の `useState` や非制御の `input` だけで値を持っていると、次に開いたときは初期値に戻ります。親コンポーネントや外部ストアに値を置いている場合は残ります。

中身を残すなら `unmountOnExit={false}` を渡し、3.37.0で追加された `hideMode` で隠し方を選びます。jsdom上で開閉した後の content は次のとおりでした。

| 指定                                        | 閉じた後の content | 中の副作用             |
| ----------------------------------------- | ------------- | ----------------- |
| 既定（unmountOnExit: true）                   | DOMから削除       | 破棄                |
| unmountOnExit=false（hideMode 既定）          | hidden 属性で非表示 | 動き続ける             |
| unmountOnExit=false ＋ hideMode=”activity” | display: none | Effectのクリーンアップを実行 |

```
<Drawer.Root
  open={open}
  onOpenChange={(e) => setOpen(e.open)}
  unmountOnExit={false}
  hideMode="activity"
>
  ...
</Drawer.Root>
```

`"activity"` は React 19.2 で安定版になった `Activity` を使います。Ark UI の実装は React に `Activity` が無ければ自動で display-none 扱いに戻すので、古い React では指定しても hidden 属性になるだけです。[ReactのActivityの解説](https://react.dev/reference/react/Activity)のとおり、非表示の間は中のEffectのクリーンアップが走り、再表示で再実行されます。ただし動画の一時停止やWebSocketの切断が起きるのは、それをクリーンアップに書いてある場合だけで、DOMに残る video 要素はそのままでは再生を続けます。**入力値の保持だけが目的なら hideMode は既定のままで足ります。閉じている間に購読やタイマーを止めたいときに `"activity"` を選び、停止処理をEffectのクリーンアップに書いてください。**なお `hideMode` だけを指定して `unmountOnExit` を既定のままにすると、型エラーは出ないのに何も変わりません。中身は閉じた時点で破棄されるからです。

## スワイプで閉じるボトムシートが必要な場合の選択肢

Chakra UIのDrawerは、下へスワイプして閉じる操作にも、半分の高さで止めるスナップにも対応していません。ドラッグを扱う部品が無いので、スマホアプリのようなボトムシートが要件なら別の部品を使います。

Chakra UIの開発チームが手がける Ark UI には、ジェスチャー対応の Drawer があります。[Ark UIの変更履歴](https://github.com/chakra-ui/ark/blob/main/packages/react/CHANGELOG.md)では 5.32.0（2026年2月21日）で旧 BottomSheet を置き換えて追加されました。`swipeDirection` は up / down / start / end（既定 down）、`snapPoints` の既定は `[1]` です。Chakra UI 3.37.0 の依存にも @ark-ui/react 5.39.0 が入っていますが、直接importするなら package.json に明示して入れてください。pnpm では宣言していない依存はimportできません。

```
import { Drawer } from "@ark-ui/react/drawer"
import { Portal } from "@ark-ui/react/portal"

export function SheetDrawer() {
  return (
    <Drawer.Root swipeDirection="down" snapPoints={[0.5, 1]}>
      <Drawer.Trigger>詳細を開く</Drawer.Trigger>
      <Portal>
        <Drawer.Backdrop />
        <Drawer.Positioner>
          <Drawer.Content>
            <Drawer.Grabber>
              <Drawer.GrabberIndicator />
            </Drawer.Grabber>
            <Drawer.Title>詳細</Drawer.Title>
            <p>下へスワイプすると閉じます。</p>
          </Drawer.Content>
        </Drawer.Positioner>
      </Portal>
    </Drawer.Root>
  )
}
```

[Ark UIのDrawerドキュメント](https://ark-ui.com/react/docs/components/drawer)ではステータスが Preview で、APIは今後も変わりえます。Ark UI はスタイルを持たないヘッドレス部品なので Chakra のレシピは当たらず、見た目は自前です。ほかの選択肢として、[Base UIのDrawer](https://base-ui.com/react/components/drawer)もスワイプでの閉じとスナップに対応し、MUI なら [SwipeableDrawer](https://mui.com/material-ui/react-drawer/) が使えます。Base UIの全体像は[Base UIとRadix UI・MUIの違い](/tech/details/10350/)で比べています。

ボトムシートを含むモバイル画面の操作設計から相談したい場合は、[UI/UXデザイン支援](/service/web/ui-ux/)も扱っています。

## slot recipeによるDrawer既定値の一括変更

画面ごとに `placement="start" size="md"` と書き続けるより、スロットレシピの `defaultVariants` を上書きして `createSystem` に組み込むほうが保守が楽です。スロット名は手書きせず `drawerAnatomy.keys()` から取ると、trigger のような部品の書き漏れを防げます。

```
import { createSystem, defaultConfig, defineSlotRecipe } from "@chakra-ui/react"
import { drawerAnatomy } from "@chakra-ui/react/anatomy"

const drawerSlotRecipe = defineSlotRecipe({
  slots: drawerAnatomy.keys(),
  base: {
    content: { bg: "gray.50" },
  },
  defaultVariants: {
    size: "md",
    placement: "start",
  },
})

export const system = createSystem(defaultConfig, {
  theme: {
    slotRecipes: { drawer: drawerSlotRecipe },
  },
})
```

`ChakraProvider` の `value` にこの system を渡すと、個別に placement や size を渡していないDrawerは、左出し（LTRの場合）・最大幅32rem（ルート文字サイズ16pxで512px）が既定になります。v2の `extendTheme` と `components.Drawer.baseStyle` は無くなり、指定の単位がコンポーネントからスロットへ変わりました。スタイルを完全に自前で持つ構成なら[Headless UIのReact・Vue版の違いと使い方](/tech/details/9449/)も判断材料になります。

## よくある質問

### ドロワーUIとは何ですか？

画面の端から引き出しのように滑り出すパネル型のUIです。元の画面を残したまま、ナビゲーションメニューやカート、絞り込み条件などを重ねて表示します。

### v2のDrawerコードはv3でそのまま動きますか？

動きません。3.37.0 でv2記法を型検査すると5件のエラーが出ます。DrawerContent や DrawerBody のimportは通ってしまうので、Drawer関連のimportを全件ドット記法へ置き換えてください。

### Chakra UIのDrawerとDialogは何が違いますか？

どちらも Ark UI の Dialog が土台で、違いはスロットレシピだけです。Drawer は画面端へ寄せてスライドさせ、フォーカストラップや `modal` などのプロパティは共通です。

### useDisclosureはv3でも使えますか？

使えます。戻り値は open / onOpen / onClose / onToggle / setOpen の5つで、v2の isOpen はありません。Drawer.Root の onOpenChange はオブジェクトを受け取るので、`(e) => setOpen(e.open)` のように中の open を読んでください。

### Chakra UIのDrawerはスワイプで閉じられますか？

3.37.0 のDrawerは対応していません。ボトムシートが必要なら Ark UI の Drawer（`@ark-ui/react/drawer`）が `swipeDirection` と `snapPoints` を持ちますが、ステータスは Preview で、スタイルは自前です。

## 関連記事

- [Chakra UIとは？v3の使い方・インストール手順とv2移行の注意点【2026年10月】](/tech/details/3059/)
- [ドロワーUIとは？モーダル・ダイアログとの違いと使い分け、dialog要素での実装](/tech/details/7075/)
- [Base UI（React）とは？Radix UI・MUIとの違いと使い方【v1.9対応】](/tech/details/10350/)
- [Headless UIとは？React・Vue版の違いとTailwind連携・Next.jsでの使い方【v2.2対応】](/tech/details/9449/)
- [レスポンシブデザインの作り方｜メディアクエリとブレークポイント設計の実装手順](/tech/details/15329/)

---

出典: [Chakra UI Drawerの使い方｜v3（3.37）の実装とv2からの移行・placement設定](<https://www.issoh.co.jp/tech/details/4398/>)（株式会社一創）
