Closed4

dialog要素のあれこれ

けのびけのび

dialog 要素を使ってモーダルの実装を考えていた時にバックドロップ ::backdrop 擬似要素が表示されないことがあり、 調べると showModal() を実行してダイアログを開く必要があるとわかった。

その時のメモをここに記す。

けのびけのび

https://developer.mozilla.org/en-US/docs/Web/HTML/Element/dialog

Indicates that the dialog is active and can be interacted with. When the open attribute is not set, the dialog shouldn't be shown to the user. It is recommended to use the .show() or .showModal() methods to render dialogs, rather than the open attribute. If a <dialog> is opened using the open attribute, it will be non-modal.

MDNのテキストを見る限り、 open 属性の指定で開閉制御するのではなく、 .show() または .showModal() のメソッドを用いることが推奨されている。 open 属性で開いた場合 モーダル にはならない。

モーダル にならないとはなんなのか。🧐

モーダル、非モーダルの2パターンがある模様。それぞれ見ていこう。

けのびけのび

非モーダル(モーダルレスなダイアログ)の例

open 属性の指定で開閉制御するケースです。

ダイアログ本体は表示はされますが、前述の通りバックドロップが表示されません。

import { useState } from 'react'

const Sample = () => {
  const [open, setOpen] = useState(false)

  return (
    <div>
      <button type='button' onClick={() => setOpen(true)}>
        ダイアログを開く [open属性で開閉制御]
      </button>
      <dialog open={open}>
        <p>open属性で開閉制御</p>
        <button type='button' onClick={() => setOpen(false)}>
          ダイアログを閉じる
        </button>
      </dialog>
    </div>
  )
}

ちなみに、.show() で開いた場合も非モーダルに相当しているようだ。

import { useRef } from 'react'
import type { RefObject } from 'react'

function useDialog(dialogRef: RefObject<HTMLDialogElement>) {
  return {
    open: () => {
      // .show() で開く
      dialogRef.current?.show()
    },
    close: () => {
      dialogRef.current?.close()
    },
  }
}

const Sample = () => {
  const dialogRef = useRef<HTMLDialogElement | null>(null)
  const { open, close } = useDialog(dialogRef)

  return (
    <div>
      <button type='button' onClick={() => open()}>
        ダイアログを開く [show()とclose()で開閉制御]
      </button>
      <dialog ref={dialogRef}>
        <p>show()とclose()で開閉制御</p>
        <button type='button' onClick={() => close()}>
          ダイアログを閉じる
        </button>
      </dialog>
    </div>
  )
}

プレビュー

けのびけのび

モーダルの例

showModal() で開いた場合の例です。

特徴は次のとおりです。

  • Esc キーで閉じることができる。
  • モーダル背面の要素をクリックできない。
  • バックドロップが表示される。また、バックドロップのスタイリングも可能。
import { useRef } from 'react'
import type { RefObject } from 'react'

function useDialog(dialogRef: RefObject<HTMLDialogElement>) {
  return {
    open: () => {
      // .showModal() で開く
      dialogRef.current?.showModal()
    },
    close: () => {
      dialogRef.current?.close()
    },
  }
}

const Sample = () => {
  const dialogRef = useRef<HTMLDialogElement | null>(null)
  const { open, close } = useDialog(dialogRef)

  return (
    <div>
      <button type='button' onClick={() => open()}>
        ダイアログを開く [showModal()とclose()で開閉制御]
      </button>
      <dialog ref={dialogRef}>
        <p>showModal()とclose()で開閉制御</p>
        <button type='button' onClick={() => close()}>
          ダイアログを閉じる
        </button>
      </dialog>
    </div>
  )
}

プレビュー

このスクラップは2ヶ月前にクローズされました