Modal Component
CSS-only Tailwind CSS modal using native <dialog>. Responsive sizing, backdrop, and focus trap. No JavaScript for basic usage. WCAG AA accessible, works with Django, HTMX, Laravel, React, and any stack.
模態元件在對焦的覆蓋視窗中顯示重要資訊或請求使用者操作。模態基於語義 HTML 對話方塊元素構建,支援動畫、可自訂定位和背景覆蓋。 Frutjam 模態系統可透過鍵盤導航和陷阱焦點完全訪問,使其成為確認、表單和警報對話框的理想選擇。
僅 CSS,無需 JavaScript。 WCAG AA 可存取且與框架無關 - 可與 Django、HTMX、Laravel、React 和任何堆疊配合使用。
| 班級 | 類型 | 描述 |
|---|---|---|
| modal | 根據 | 全螢幕對話框覆蓋容器 |
| modal-content | 修飾符 | 帶有填充和背景的內面板 |
| modal-backdrop | 修飾符 | 點選關閉背景覆蓋 |
| modal-top | 修飾符 | 將內容與螢幕頂部對齊 |
| modal-bottom | 修飾符 | 將內容與螢幕底部對齊 |
| modal-start | 修飾符 | 將內容左對齊 |
| modal-end | 修飾符 | 將內容右對齊 |
| modal-center | 修飾符 | 水平居中 |
| modal-middle | 修飾符 | 垂直居中 |
| modal-slide-up | 風格 | 上滑入口動畫 |
| modal-slide-down | 風格 | 下滑入口動畫 |
| modal-slide-start | 風格 | 從左側滑入動畫 |
| modal-slide-end | 風格 | 從右側動畫滑入 |
基本用法
將唯一的 ID 新增至 HTML 元素,然後在 JavaScript 中使用該 id 呼叫 myModal.showModal() 開啟模式,並使用 myModal.close() 關閉模式。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | <dialog class="modal modal-center lg:modal-middle modal-slide-end lg:modal-slide-down" id="toggleModal"> <div class="modal-content"> <div class="flex justify-between items-center gap-3"> <div class="font-medium heading-lg">Dialog modal</div> <button type="button" class="btn btn-xs btn-square btn-rounded btn-ghost" onclick="toggleModal.close()"> <svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"> <path d="M18 6 6 18"></path> <path d="m6 6 12 12"></path> </svg> </button> </div> <div class="divider my-3"></div> <p class="para">Press Esc key or close button to close the modal</p> </div> <button type="button" class="modal-backdrop" onclick="toggleModal.close()">Close Modal via Backdrop</button> </dialog> <button type="button" class="btn btn-xs" onclick="toggleModal.showModal()">Show Modal</button> |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | import { useModal } from 'frutjam/react' export default function ModalDemo() { const modal = useModal() return ( <> <button type="button" className="btn btn-xs" onClick={modal.open}>Show Modal</button> <dialog ref={modal.ref} className="modal modal-center lg:modal-middle modal-slide-end lg:modal-slide-down"> <div className="modal-content"> <div className="flex justify-between items-center gap-3"> <div className="font-medium heading-lg">Dialog modal</div> <button type="button" className="btn btn-xs btn-square btn-rounded btn-ghost" onClick={modal.close}> <svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"> <path d="M18 6 6 18"></path> <path d="m6 6 12 12"></path> </svg> </button> </div> <div className="divider my-3"></div> <p className="para">Press Esc key or close button to close the modal</p> </div> <button type="button" className="modal-backdrop" onClick={modal.close}>Close Modal via Backdrop</button> </dialog> </> ) } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | <script setup> import { ref } from 'vue' const dialogRef = ref(null) </script> <template> <button type="button" class="btn btn-xs" @click="dialogRef.showModal()">Show Modal</button> <dialog ref="dialogRef" class="modal modal-center lg:modal-middle modal-slide-end lg:modal-slide-down"> <div class="modal-content"> <div class="flex justify-between items-center gap-3"> <div class="font-medium heading-lg">Dialog modal</div> <button type="button" class="btn btn-xs btn-square btn-rounded btn-ghost" @click="dialogRef.close()"> <svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"> <path d="M18 6 6 18"></path> <path d="m6 6 12 12"></path> </svg> </button> </div> <div class="divider my-3"></div> <p class="para">Press Esc key or close button to close the modal</p> </div> <button type="button" class="modal-backdrop" @click="dialogRef.close()">Close Modal via Backdrop</button> </dialog> </template> |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | <script> let dialog = $state(null) </script> <button type="button" class="btn btn-xs" onclick={() => dialog.showModal()}>Show Modal</button> <dialog bind:this={dialog} class="modal modal-center lg:modal-middle modal-slide-end lg:modal-slide-down"> <div class="modal-content"> <div class="flex justify-between items-center gap-3"> <div class="font-medium heading-lg">Dialog modal</div> <button type="button" class="btn btn-xs btn-square btn-rounded btn-ghost" onclick={() => dialog.close()}> <svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"> <path d="M18 6 6 18"></path> <path d="m6 6 12 12"></path> </svg> </button> </div> <div class="divider my-3"></div> <p class="para">Press Esc key or close button to close the modal</p> </div> <button type="button" class="modal-backdrop" onclick={() => dialog.close()}>Close Modal via Backdrop</button> </dialog> |
按一下外部時關閉模態
.modal-backdrop 提供了一個可點擊的背景,當在模態內容之外點擊時,背景會關閉模態。
1 2 3 4 5 6 7 8 9 10 11 12 13 | <dialog class="modal" id="backdropModal"> <div class="modal-content"> <div class="flex justify-between items-center gap-3"> <div class="font-medium heading-lg">Dialog modal</div> </div> <div class="divider my-3"></div> <p class="para">Press Esc key or click outside to close the modal</p> </div> <button type="button" class="modal-backdrop" onclick="backdropModal.close()"> Close Modal via Backdrop </button> </dialog> <button type="button" class="btn btn-xs" onclick="backdropModal.showModal()">Show Modal</button> |
模態幻燈片動畫
使用模態組件中的以下定向實用程式類,從頂部、底部、開始(LTR 中向左、RTL 中向右)或結束(LTR 中向右、RTL 向左)平滑滑入和滑出:modal-slide-top、modal-slide-bottom、modal-slide-bottom、mod-slide-bottom、<這些動畫透過使用基於模態位置的動態過渡來改善使用者體驗。
從頭開始模態幻燈片(水平)
添加 modal-slide-start 實用程式以從起始側水平滑動模態;在從左到右 (LTR) 佈局中,它從左側出現;在從右到左 (RTL) 佈局中,它從右側出現。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | <dialog class="modal modal-center lg:modal-middle modal-slide-start" id="slideStartModal"> <div class="modal-content"> <div class="flex justify-between items-center gap-3"> <div class="font-medium heading-lg">Slide start modal</div> <button type="button" class="btn btn-xs btn-square btn-rounded btn-ghost" onclick="slideStartModal.close()"> <svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"> <path d="M18 6 6 18"></path> <path d="m6 6 12 12"></path> </svg> </button> </div> <div class="divider my-3"></div> <p class="para">Horizontally slides the modal in and out from the start side.</p> </div> </dialog> <button type="button" class="btn btn-xs" onclick="slideStartModal.showModal()">Show Modal</button> |
從末端開始模態滑動(水平)
在模態組件中添加 modal-slide-end 實用程序,使模態從末端水平滑動;在從左到右 (LTR) 佈局中,它從右側出現;在從右到左 (RTL) 佈局中,它從左側出現。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | <dialog class="modal modal-center lg:modal-middle modal-slide-end" id="slideEndModal"> <div class="modal-content"> <div class="flex justify-between items-center gap-3"> <div class="font-medium heading-lg">Slide end modal</div> <button type="button" class="btn btn-xs btn-square btn-rounded btn-ghost" onclick="slideEndModal.close()"> <svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"> <path d="M18 6 6 18"></path> <path d="m6 6 12 12"></path> </svg> </button> </div> <div class="divider my-3"></div> <p class="para">Horizontally slides the modal in and out from the end side.</p> </div> </dialog> <button type="button" class="btn btn-xs" onclick="slideEndModal.showModal()">Show Modal</button> |
從底部滑動(垂直):modal-slide-up
方向:從底部垂直滑入
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | <dialog class="modal modal-center lg:modal-middle modal-slide-up" id="slideUpModal"> <div class="modal-content"> <div class="flex justify-between items-center gap-3"> <div class="font-medium heading-lg">Slide up modal</div> <button type="button" class="btn btn-xs btn-square btn-rounded btn-ghost" onclick="slideUpModal.close()"> <svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"> <path d="M18 6 6 18"></path> <path d="m6 6 12 12"></path> </svg> </button> </div> <div class="divider my-3"></div> <p class="para">Vertically slides the modal in and out from the bottom.</p> </div> </dialog> <button type="button" class="btn btn-xs" onclick="slideUpModal.showModal()">Show Modal</button> |
從頂部滑動(垂直)
在模態元件中加入 modal-slide-down 公用程式以從頂部垂直滑入。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | <dialog class="modal modal-center lg:modal-middle modal-slide-down" id="slideDownModal"> <div class="modal-content"> <div class="flex justify-between items-center gap-3"> <div class="font-medium heading-lg">Slide down modal</div> <button type="button" class="btn btn-xs btn-square btn-rounded btn-ghost" onclick="slideDownModal.close()"> <svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"> <path d="M18 6 6 18"></path> <path d="m6 6 12 12"></path> </svg> </button> </div> <div class="divider my-3"></div> <p class="para">Vertically slides the modal in and out from the top.</p> </div> </dialog> <button type="button" class="btn btn-xs" onclick="slideDownModal.showModal()">Show Modal</button> |
用於通知的滑動動畫模式的範例用法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | <dialog class="modal modal-end modal-top modal-slide-end" id="notificationSlideModal"> <div class="modal-content"> <div class="flex justify-between items-center gap-3"> <div class="font-medium heading-lg">Notification modal</div> <button type="button" class="btn btn-xs btn-square btn-rounded btn-ghost" onclick="notificationSlideModal.close()"> <svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"> <path d="M18 6 6 18"></path> <path d="m6 6 12 12"></path> </svg> </button> </div> </div> </dialog> <button type="button" class="btn btn-xs" onclick="notificationSlideModal.showModal()">Show Modal</button> |
模態展示位置
預設情況下,模態元件位於螢幕中央,但可以根據使用情況使用水平類別 modal-start、modal-center 或 modal-end 以及垂直類別 modal-top、modal-middle 或 modal-bottom。佈局的設計考慮了 RTL 和 LTR 相容性,使模式能夠適應不同的語言方向和佈局。
使用modal-start、modal-center或modal-end進行水平放置,使用modal-top、modal-middle或modal-bottom進行垂直放置。這些類別應用於模態組件。
左上角模態位置
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | <dialog class="modal modal-start modal-top" id="topLeftModal"> <div class="modal-content"> <div class="flex justify-between items-center gap-3"> <div class="font-medium heading-lg">Modal placement top left</div> <button type="button" class="btn btn-xs btn-square btn-rounded btn-ghost" onclick="topLeftModal.close()"> <svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"> <path d="M18 6 6 18"></path> <path d="m6 6 12 12"></path> </svg> </button> </div> <div class="divider my-3"></div> <p class="para">Modal placed at the top left corner of the screen</p> </div> <button type="button" class="modal-backdrop" onclick="topLeftModal.close()"> Close Modal via Backdrop </button> </dialog> <button type="button" class="btn btn-xs" onclick="topLeftModal.showModal()">Show Modal</button> |
頂部中心模態放置
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | <dialog class="modal modal-center modal-top" id="topCenterModal"> <div class="modal-content"> <div class="flex justify-between items-center gap-3"> <div class="font-medium heading-lg">Modal placement top center</div> <button type="button" class="btn btn-xs btn-square btn-rounded btn-ghost" onclick="topCenterModal.close()"> <svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"> <path d="M18 6 6 18"></path> <path d="m6 6 12 12"></path> </svg> </button> </div> <div class="divider my-3"></div> <p class="para">Modal placed at the top center corner of the screen</p> </div> <button type="button" class="modal-backdrop" onclick="topCenterModal.close()"> Close Modal via Backdrop </button> </dialog> <button type="button" class="btn btn-xs" onclick="topCenterModal.showModal()">Show Modal</button> |
右上角模態位置
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | <dialog class="modal modal-end modal-top" id="topEndModal"> <div class="modal-content"> <div class="flex justify-between items-center gap-3"> <div class="font-medium heading-lg">Modal placement top end</div> <button type="button" class="btn btn-xs btn-square btn-rounded btn-ghost" onclick="topEndModal.close()"> <svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"> <path d="M18 6 6 18"></path> <path d="m6 6 12 12"></path> </svg> </button> </div> <div class="divider my-3"></div> <p class="para">Modal placed at the top end corner of the screen</p> </div> <button type="button" class="modal-backdrop" onclick="topEndModal.close()"> Close Modal via Backdrop </button> </dialog> <button type="button" class="btn btn-xs" onclick="topEndModal.showModal()">Show Modal</button> |
居中左模態放置
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | <dialog class="modal modal-start modal-middle" id="startCenterModal"> <div class="modal-content"> <div class="flex justify-between items-center gap-3"> <div class="font-medium heading-lg">Modal placement left center</div> <button type="button" class="btn btn-xs btn-square btn-rounded btn-ghost" onclick="startCenterModal.close()"> <svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"> <path d="M18 6 6 18"></path> <path d="m6 6 12 12"></path> </svg> </button> </div> <div class="divider my-3"></div> <p class="para">Modal placed at the start center corner of the screen</p> </div> <button type="button" class="modal-backdrop" onclick="startCenterModal.close()"> Close Modal via Backdrop </button> </dialog> <button type="button" class="btn btn-xs" onclick="startCenterModal.showModal()">Show Modal</button> |
居中右模態放置
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | <dialog class="modal modal-end modal-middle" id="endCenterModal"> <div class="modal-content"> <div class="flex justify-between items-center gap-3"> <div class="font-medium heading-lg">Modal placement right center</div> <button type="button" class="btn btn-xs btn-square btn-rounded btn-ghost" onclick="endCenterModal.close()"> <svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"> <path d="M18 6 6 18"></path> <path d="m6 6 12 12"></path> </svg> </button> </div> <div class="divider my-3"></div> <p class="para">Modal placed at the end center corner of the screen</p> </div> <button type="button" class="modal-backdrop" onclick="endCenterModal.close()"> Close Modal via Backdrop </button> </dialog> <button type="button" class="btn btn-xs" onclick="endCenterModal.showModal()">Show Modal</button> |
左下角模態位置
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | <dialog class="modal modal-start modal-bottom" id="bottomStartModal"> <div class="modal-content"> <div class="flex justify-between items-center gap-3"> <div class="font-medium heading-lg">Modal placement bottom start</div> <button type="button" class="btn btn-xs btn-square btn-rounded btn-ghost" onclick="bottomStartModal.close()"> <svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"> <path d="M18 6 6 18"></path> <path d="m6 6 12 12"></path> </svg> </button> </div> <div class="divider my-3"></div> <p class="para">Modal placed at the bottom start corner of the screen</p> </div> <button type="button" class="modal-backdrop" onclick="bottomStartModal.close()"> Close Modal via Backdrop </button> </dialog> <button type="button" class="btn btn-xs" onclick="bottomStartModal.showModal()">Show Modal</button> |
底部中心模態放置
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | <dialog class="modal modal-center modal-bottom" id="bottomCenterModal"> <div class="modal-content"> <div class="flex justify-between items-center gap-3"> <div class="font-medium heading-lg">Modal placement bottom center</div> <button type="button" class="btn btn-xs btn-square btn-rounded btn-ghost" onclick="bottomCenterModal.close()"> <svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"> <path d="M18 6 6 18"></path> <path d="m6 6 12 12"></path> </svg> </button> </div> <div class="divider my-3"></div> <p class="para">Modal placed at the bottom center corner of the screen</p> </div> <button type="button" class="modal-backdrop" onclick="bottomCenterModal.close()"> Close Modal via Backdrop </button> </dialog> <button type="button" class="btn btn-xs" onclick="bottomCenterModal.showModal()">Show Modal</button> |
右下模態位置
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | <dialog class="modal modal-end modal-bottom" id="bottomEndModal"> <div class="modal-content"> <div class="flex justify-between items-center gap-3"> <div class="font-medium heading-lg">Modal placement bottom center</div> <button type="button" class="btn btn-xs btn-square btn-rounded btn-ghost" onclick="bottomEndModal.close()"> <svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"> <path d="M18 6 6 18"></path> <path d="m6 6 12 12"></path> </svg> </button> </div> <div class="divider my-3"></div> <p class="para">Modal placed at the bottom center corner of the screen</p> </div> <button type="button" class="modal-backdrop" onclick="bottomEndModal.close()"> Close Modal via Backdrop </button> </dialog> <button type="button" class="btn btn-xs" onclick="bottomEndModal.showModal()">Show Modal</button> |
桌面和行動螢幕的模態響應式定位
根據您的使用案例,您可以將模態框放置在桌面或行動裝置上的任何位置,例如桌面中心和行動裝置頂部中心。
1 2 3 4 5 6 7 8 9 10 11 12 13 | <dialog class="modal modal-center modal-top lg:modal-center lg:modal-middle" id="responsiveModal"> <div class="modal-content"> <div class="flex justify-between items-center gap-3"> <div class="font-medium heading-lg">Responsive modal</div> </div> <div class="divider my-3"></div> <p class="para">Resize the modal to a small screen to see the change in modal position.</p> </div> <button type="button" class="modal-backdrop" onclick="responsiveModal.close()"> Close Modal via Backdrop </button> </dialog> <button type="button" class="btn btn-xs" onclick="responsiveModal.showModal()">Show Modal</button> |
基於語言方向的模態定位
根據語言方向(LTR 或 RTL)將模態框放置在螢幕上的任意位置。
LTR 和 RTL 中右對齊且垂直居中
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | <dialog class="modal ltr:modal-end ltr:modal-middle rtl:modal-start lg:modal-middle" id="ltrModal"> <div class="modal-content"> <div class="flex justify-between items-center gap-3"> <div class="font-medium heading-lg">Responsive modal</div> </div> <div class="divider my-3"></div> <p class="para"> Changing <code>dir="rtl"</code> in the HTML will have no effect on the modal's the position because the layout is controlled by utility classes: <code>modal-end</code> for the LTR variant and <code>modal-start</code> for the RTL variant. </p> </div> <button type="button" class="modal-backdrop" onclick="ltrModal.close()"> Close Modal via Backdrop </button> </dialog> <button type="button" class="btn btn-xs" onclick="ltrModal.showModal()">Show Modal</button> |
根據螢幕尺寸和語言方向放置模態框
1 2 3 4 5 6 7 8 9 10 11 12 13 | <dialog class="modal ltr:modal-center lg:ltr:modal-start ltr:modal-top lg:ltr:modal-middle rtl:modal-center lg:rtl:modal-start rtl:modal-bottom lg:rtl:modal-middle" id="mixedModal"> <div class="modal-content"> <div class="flex justify-between items-center gap-3"> <div class="font-medium heading-lg">Responsive modal</div> </div> <div class="divider my-3"></div> <p class="para">Change the screen and screen direction to see the change in modal position.</p> </div> <button type="button" class="modal-backdrop" onclick="mixedModal.close()"> Close Modal via Backdrop </button> </dialog> <button type="button" class="btn btn-xs" onclick="mixedModal.showModal()">Show Modal</button> |