Skip to content
API 风格:

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オーバーレイクリックで閉じるかどうかbooleantrue
showClose閉じるボタンを表示するかどうかbooleantrue
teleportTargetTeleport の転送先(セレクターまたは要素。デフォルトは body)string | HTMLElement'body'
lockScrollページスクロールをロックするかどうかbooleantrue
closeOnEscEsc で閉じるかどうかbooleantrue
themeVarsコンポーネントレベルのテーマ変数。ConfigProvider の設定を上書きします{ [x: string]: string; }—
bgPatternコンポーネントレベルの背景紋様。ConfigProvider の設定を上書きしますstring—
sxsx クイックレイアウトプロパティ(パネルに作用)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'

国風の美で、コードの基を築く