Madogiwa Blog

主に技術系の学習メモに使っていきます。

Vue.js: Vue Final Modalでモーダルを実装するメモ🗒

Vue.jsを使っていてモーダルを実装する際にアクセシビリティ等々考慮したりすると実装が難しかったりするので何かしらライブラリを利用したいと思ったときにVue Final ModalがVue3にも対応していてサクッと実装できて便利だったのでメモ📝

vue-final-modal.org

使い方

以下の公式ガイド通りですが使い方をメモ📝

install

$ npm install vue-final-modal

使い方

デフォルトのデザイン付きのModalを使う場合には以下の公式サンプル通りに以下のCSSを読み込ませて、

import 'vue-final-modal/style.css'

VueFinalModalを使ってあげれば大丈夫でした。

<script setup lang="ts">
  import { VueFinalModal } from 'vue-final-modal'
  defineProps<{
    title?: string
  }>()
  const emit = defineEmits<{
    (e: 'confirm'): void
  }>()
  </script>
  <template>
    <VueFinalModal
      class="flex justify-center items-center"
      content-class="flex flex-col max-w-xl mx-4 p-4 bg-white dark:bg-gray-900 border dark:border-gray-700 rounded-lg space-y-2"
    >
      <h1 class="text-xl">
        {{ title }}
      </h1>
      <slot />
      <button class="mt-1 ml-auto px-2 border rounded-lg" @click="emit('confirm')">
        Confirm
      </button>
    </VueFinalModal>
  </template>

自分は以下のような感じでComponent内でstyleをimportして、外部コンポーネントが直接VueFinalModalに依存するのが嫌だったのでWrapするComponentを用意して利用できるようにしました。

<template>
  <VueFinalModal class="common-modal" @closed="() => $emit('close')">
    <div class="common-modal__body">
      <slot />
    </div>
  </VueFinalModal>
</template>
<script setup lang="ts">
import "vue-final-modal/style.css";
import { VueFinalModal } from "vue-final-modal";

defineEmits(["close"]);
</script>
<!-- NOTE: VueFinalModalがScoped CSSでstyleできないようなのでscopedを外している -->
<!-- https://github.com/vue-final/vue-final-modal/issues/312 -->
<style lang="scss">
@use "@css/variables" as *;

.common-modal {
  display: flex;
  justify-content: center;
  align-items: center;

  &__body {
    background-color: $white-color;
  }
}
</style>

以下のissueにある通りVue Final ModalがVue 3のteleportを利用しておりscoped CSSを利用するとモーダルにスタイルが当たらないようだったのでscopedを外すようにしています。

github.com

おそらくteleportでコンポーネント外にモーダルで表示する要素が移動してscopedの範囲外になってしまうためと思われる🤔(defaultだとbody直下に移動してしまうっぽい)

ja.vuejs.org

vue-final-modal.org