Drawer ドロワー
画面の端からスライドインするサイドパネルです。Dialog よりも端に寄った一時操作(詳細、フィルター、ウィザード手順)に適しています。Dialog と同様に role="dialog" + aria-modal="true" を採用し、フォーカスはパネル内に留まり、Esc とオーバーレイクリックのどちらでも閉じられます。
基本的な使い方
右側ドロワー
vue
<template>
<LhButton @click="basic = true">ドロワーを開く</LhButton>
<LhDrawer v-model="basic" title="注文の詳細">
<p>ここにドロワーのメインコンテンツを配置します。</p>
</LhDrawer>
</template>
<script setup lang="ts">
import { ref } from 'vue'
const basic = ref(false)
</script>vue
<script>
export default {
data() {
return { basic: false }
},
}
</script>
<template>
<LhButton @click="basic = true">ドロワーを開く</LhButton>
<LhDrawer v-model="basic" title="注文の詳細">
<p>ここにドロワーのメインコンテンツを配置します。</p>
</LhDrawer>
</template>四方向
right / left / top / bottom
vue
<script setup lang="ts">
import { ref } from 'vue'
const dirVisible = ref(false)
const direction = ref<'right' | 'left' | 'top' | 'bottom'>('right')
const size = ref('40%')
function openDir(d: 'right' | 'left' | 'top' | 'bottom') {
direction.value = d
dirVisible.value = true
}
</script>
<template>
<!-- 右側ドロワーを開く -->
<LhButton @click="openDir('right')">right</LhButton>
<!-- 左側ドロワーを開く -->
<LhButton @click="openDir('left')">left</LhButton>
<!-- 上部ドロワーを開く -->
<LhButton @click="openDir('top')">top</LhButton>
<!-- 下部ドロワーを開く -->
<LhButton @click="openDir('bottom')">bottom</LhButton>
<!-- 指定方向にスライドイン -->
<LhDrawer v-model="dirVisible" :title="`${direction} ドロワー`" :direction="direction" :size="size">
<p>現在の方向:{{ direction }}</p>
</LhDrawer>
</template>vue
<script>
export default {
data() {
return { dirVisible: false, direction: 'right', size: '40%' }
},
methods: {
openDir(d) {
this.direction = d
this.dirVisible = true
},
},
}
</script>
<template>
<!-- 右側ドロワーを開く -->
<LhButton @click="openDir('right')">right</LhButton>
<!-- 左側ドロワーを開く -->
<LhButton @click="openDir('left')">left</LhButton>
<!-- 上部ドロワーを開く -->
<LhButton @click="openDir('top')">top</LhButton>
<!-- 下部ドロワーを開く -->
<LhButton @click="openDir('bottom')">bottom</LhButton>
<!-- 指定方向にスライドイン -->
<LhDrawer v-model="dirVisible" :title="`${direction} ドロワー`" :direction="direction" :size="size">
<p>現在の方向:{{ direction }}</p>
</LhDrawer>
</template>カスタムサイズとフッター
size と footer スロット
vue
<script setup lang="ts">
import { ref } from 'vue'
const sized = ref(false)
</script>
<template>
<!-- 480px 幅のドロワーを開く -->
<LhButton @click="sized = true">480px 幅のドロワー</LhButton>
<!-- 固定サイズのドロワー。底部は操作領域 -->
<LhDrawer v-model="sized" title="フィルター条件" :size="480">
<LhInput placeholder="名称で絞り込み" />
<LhInput placeholder="タグで絞り込み" />
<template #footer>
<LhButton @click="sized = false">キャンセル</LhButton>
<LhButton type="primary" @click="sized = false">フィルターを適用</LhButton>
</template>
</LhDrawer>
</template>vue
<script>
export default {
data() {
return { sized: false }
},
}
</script>
<template>
<!-- 480px 幅のドロワーを開く -->
<LhButton @click="sized = true">480px 幅のドロワー</LhButton>
<!-- 固定サイズのドロワー。底部は操作領域 -->
<LhDrawer v-model="sized" title="フィルター条件" :size="480">
<LhInput placeholder="名称で絞り込み" />
<LhInput placeholder="タグで絞り込み" />
<template #footer>
<LhButton @click="sized = false">キャンセル</LhButton>
<LhButton type="primary" @click="sized = false">フィルターを適用</LhButton>
</template>
</LhDrawer>
</template>
sizeに数字を渡すと px、文字列を渡すとパーセンテージ('40%'など)として扱われます。左右方向は幅、上下方向は高さに作用します。
動作スイッチ
mask-closable でオーバーレイクリックによるクローズを禁止、show-close で右上の閉じるボタンを非表示、close-on-esc で Esc クローズを無効化、lock-scroll で開いているときのページスクロールをロックしない、teleport-target でマウント先を指定できます。
動作スイッチ
vue
<script setup lang="ts">
import { ref } from 'vue'
const adv1 = ref(false)
const adv2 = ref(false)
const adv3 = ref(false)
</script>
<template>
<!-- 「ボタンのみで閉じる」ドロワーを開く -->
<LhButton @click="adv1 = true">ボタンのみで閉じる</LhButton>
<!-- 「スクロールをロックしない」ドロワーを開く -->
<LhButton @click="adv2 = true">スクロールをロックしない</LhButton>
<!-- オーバーレイクリックと Esc では閉じない -->
<LhDrawer
v-model="adv1"
title="ボタンのみで閉じる"
:mask-closable="false"
:show-close="false"
:close-on-esc="false"
>
<p>オーバーレイクリックと Esc では閉じられず、ボタンからのみ閉じられます。</p>
<template #footer>
<LhButton type="primary" @click="adv1 = false">閉じる</LhButton>
</template>
</LhDrawer>
<!-- 開いている間もページはスクロール可能 -->
<LhDrawer v-model="adv2" title="スクロールをロックしない" :lock-scroll="false">
<p>ドロワーを開いている間もページをスクロールできます。</p>
</LhDrawer>
<!-- 指定コンテナにマウント -->
<LhDrawer v-model="adv3" title="マウント先を指定" teleport-target="#drawer-host">
<p>パネルは id が drawer-host のコンテナ内に転送されます。</p>
</LhDrawer>
</template>vue
<script>
export default {
data() {
return { adv1: false, adv2: false, adv3: false }
},
}
</script>
<template>
<!-- 「ボタンのみで閉じる」ドロワーを開く -->
<LhButton @click="adv1 = true">ボタンのみで閉じる</LhButton>
<!-- 「スクロールをロックしない」ドロワーを開く -->
<LhButton @click="adv2 = true">スクロールをロックしない</LhButton>
<!-- オーバーレイクリックと Esc では閉じない -->
<LhDrawer
v-model="adv1"
title="ボタンのみで閉じる"
:mask-closable="false"
:show-close="false"
:close-on-esc="false"
>
<p>オーバーレイクリックと Esc では閉じられず、ボタンからのみ閉じられます。</p>
<template #footer>
<LhButton type="primary" @click="adv1 = false">閉じる</LhButton>
</template>
</LhDrawer>
<!-- 開いている間もページはスクロール可能 -->
<LhDrawer v-model="adv2" title="スクロールをロックしない" :lock-scroll="false">
<p>ドロワーを開いている間もページをスクロールできます。</p>
</LhDrawer>
<!-- 指定コンテナにマウント -->
<LhDrawer v-model="adv3" title="マウント先を指定" teleport-target="#drawer-host">
<p>パネルは id が drawer-host のコンテナ内に転送されます。</p>
</LhDrawer>
</template>Drawer API
Props
| プロパティ | 説明 | 型 | デフォルト値 |
|---|---|---|---|
| modelValue | 表示するかどうか(v-model) | boolean | — |
| title | タイトル(header スロットも使用可) | string | — |
| direction | 方向 | "right" | "left" | "top" | "bottom" | 'right' |
| size | サイズ:数字は px、文字列はパーセンテージに対応 | string | number | '30%' |
| maskClosable | オーバーレイクリックで閉じるかどうか | boolean | true |
| showClose | 閉じるボタンを表示するかどうか | boolean | true |
| teleportTarget | Teleport の転送先(セレクターまたは要素。デフォルトは body) | string | HTMLElement | 'body' |
| lockScroll | ページスクロールをロックするかどうか | boolean | true |
| closeOnEsc | Esc で閉じるかどうか | boolean | true |
| themeVars | コンポーネントレベルのテーマ変数。ConfigProvider の設定を上書きします | { [x: string]: string; } | — |
| bgPattern | コンポーネントレベルの背景紋様。ConfigProvider の設定を上書きします | string | — |
| sx | sx クイックレイアウトプロパティ(パネルに作用) | LhSxProps | — |
Events
| イベント | 説明 | 引数 |
|---|---|---|
| update:model-value | 表示・非表示の変化 | (value: boolean) |
| open | 開いた後にトリガー | — |
| close | 閉じた後にトリガー | — |
Slots
| スロット | 説明 |
|---|---|
| default | メインコンテンツ |
| header | カスタムヘッダー(タイトル領域を含む) |
| footer | カスタムフッター操作領域 |
Methods
| メソッド | 説明 |
|---|---|
| open | プログラムによるオープン |
| close | プログラムによるクローズ |
アクセシビリティ
role="dialog"+aria-modal="true"。タイトルがある場合はaria-labelledbyで関連付け、ない場合は言語パックdrawer.titleを aria-label のフォールバックとします- 開くとフォーカスがパネル内の最初のフォーカス可能要素に移動し、Tab はパネル内で循環します。閉じた後はトリガーのフォーカスに戻ります
- Esc で閉じられます(
close-on-escでこの動作を無効化可能)。オーバーレイは装飾的(aria-hidden)です - 閉じるボタンは実際の
<button>で、aria-label は言語パックdrawer.closeから取得します - スライドイン・スライドアウトのアニメーションは
prefers-reduced-motion下では純フェードに切り替わります
型定義
このコンポーネントが外部にエクスポートする TypeScript の型構造を以下に示します(packages/components/drawer/src/types.ts および @lh-ui/share/core/* のソースから自動抽出。各エントリーをクリックすると完全な定義が表示されます。プロパティの説明は上の Props 表を参照してください):
LhDrawerProps
ts
/**
* Drawer コンポーネントの Props
*/
export interface LhDrawerProps {
/** 表示するかどうか(v-model) */
modelValue?: boolean
/** タイトル */
title?: string
/** 方向 */
direction?: LhDrawerDirection
/** サイズ:数字は px、文字列はパーセンテージに対応 */
size?: string | number
/** オーバーレイクリックで閉じるかどうか */
maskClosable?: boolean
/** 閉じるボタンを表示するかどうか */
showClose?: boolean
/** Teleport の転送先(セレクターまたは要素。デフォルトは body) */
teleportTarget?: string | HTMLElement
/** ページスクロールをロックするかどうか */
lockScroll?: boolean
/** Esc で閉じるかどうか */
closeOnEsc?: boolean
/** コンポーネントレベルのテーマ変数。ConfigProvider の設定を上書き */
themeVars?: Record<string, string>
/** コンポーネントレベルの背景紋様。ConfigProvider の設定を上書き */
bgPattern?: string
/** sx クイックレイアウトプロパティ(パネルに作用) */
sx?: LhSxProps
}LhDrawerDirection (@lh-ui/share/core/drawer (logic.ts) より)
ts
/**
* Drawer の純関数ロジック(フレームワーク非依存)
*/
/** ドロワーの方向 */
export type LhDrawerDirection = 'right' | 'left' | 'top' | 'bottom'