小号对话框
max-width 360px,Esc / 点击遮罩可关闭
焦点已锁定在对话框内:Tab 会在关闭钮与底部按钮之间循环,关闭后焦点还原到触发按钮。
默认对话框
max-width 480px
面板进场为 dialogScaleIn 200ms:scale(.96) translateY(8px) → scale(1) translateY(0)。
同时只允许打开一个浮层对话框——打开另一个会自动关掉当前这个。
大号对话框
max-width 640px,内容超高时 modal-body 内部滚动
背景已滚动锁定(body overflow 关闭时恢复旧值)。
尺寸档:modal--sm 360 / 默认 480 / modal--lg 640 / modal--xl 800 / modal--full 全屏。
右侧 Sheet
宽 360px,translateX(40px) 滑入
Sheet 变体:modal--sheet-left / right / top / bottom,圆角只保留非贴边侧。
宽度档:默认 360px,modal--sheet-sm 280px,modal--sheet-lg 480px(上下方向为 300px / 50vh)。
<div class="demo-row"> <button class="btn" data-modal-open="demo-modal-sm">小号对话框</button> <button class="btn" data-modal-open="demo-modal-md">默认对话框</button> <button class="btn" data-modal-open="demo-modal-lg">大号对话框</button> <button class="btn" data-modal-open="demo-sheet-right">右侧 Sheet</button></div> <div class="modal-backdrop" data-modal="demo-modal-sm" hidden> <div class="modal modal--sm"> <div class="modal-header"> <div> <h3 class="modal-title">小号对话框</h3> <p class="modal-description">max-width 360px,Esc / 点击遮罩可关闭</p> </div> <button class="modal-close" data-modal-close aria-label="关闭">×</button> </div> <div class="modal-body"> <p>焦点已锁定在对话框内:Tab 会在关闭钮与底部按钮之间循环,关闭后焦点还原到触发按钮。</p> </div> <div class="modal-footer"> <button class="btn btn-sm" data-modal-close>取消</button> <button class="btn btn-sm btn-primary" data-modal-close>确定</button> </div> </div></div> <div class="modal-backdrop" data-modal="demo-modal-md" hidden> <div class="modal"> <div class="modal-header"> <div> <h3 class="modal-title">默认对话框</h3> <p class="modal-description">max-width 480px</p> </div> <button class="modal-close" data-modal-close aria-label="关闭">×</button> </div> <div class="modal-body"> <p>面板进场为 dialogScaleIn 200ms:scale(.96) translateY(8px) → scale(1) translateY(0)。</p> <p>同时只允许打开一个浮层对话框——打开另一个会自动关掉当前这个。</p> </div> <div class="modal-footer"> <button class="btn btn-sm" data-modal-close>取消</button> <button class="btn btn-sm btn-primary" data-modal-close>保存</button> </div> </div></div> <div class="modal-backdrop" data-modal="demo-modal-lg" hidden> <div class="modal modal--lg"> <div class="modal-header"> <div> <h3 class="modal-title">大号对话框</h3> <p class="modal-description">max-width 640px,内容超高时 modal-body 内部滚动</p> </div> <button class="modal-close" data-modal-close aria-label="关闭">×</button> </div> <div class="modal-body"> <p>背景已滚动锁定(body overflow 关闭时恢复旧值)。</p> <p>尺寸档:modal--sm 360 / 默认 480 / modal--lg 640 / modal--xl 800 / modal--full 全屏。</p> </div> <div class="modal-footer"> <button class="btn btn-sm" data-modal-close>关闭</button> </div> </div></div> <div class="modal-backdrop" data-modal="demo-sheet-right" hidden> <div class="modal modal--sheet-right"> <div class="modal-header"> <div> <h3 class="modal-title">右侧 Sheet</h3> <p class="modal-description">宽 360px,translateX(40px) 滑入</p> </div> <button class="modal-close" data-modal-close aria-label="关闭">×</button> </div> <div class="modal-body"> <p>Sheet 变体:modal--sheet-left / right / top / bottom,圆角只保留非贴边侧。</p> <p>宽度档:默认 360px,modal--sheet-sm 280px,modal--sheet-lg 480px(上下方向为 300px / 50vh)。</p> </div> <div class="modal-footer"> <button class="btn btn-sm" data-modal-close>关闭</button> </div> </div></div> 安装
bun add @icen.ai/ui pnpm add @icen.ai/ui npm install @icen.ai/ui yarn add @icen.ai/ui 一行引入该组件(CSS 与 behavior 自动带上,无需关心内部 CSS 文件名):
import { initModal } from '@icen.ai/ui/kit/modal';initModal(); 也可以用脚手架直接打印引入行:
bunx --bun @icen.ai/ui add modal
Astro 项目注意:kit 入口里的 CSS import 在页面 <script> 里会被 Astro 的 client bundle 摇掉——请改在布局 frontmatter 里引 CSS(import '@icen.ai/ui/components/modal.css';),JS 行为仍可走 kit。Vite SPA / webpack 项目无此问题。
用法
import { initModal, open, close } from '@icen.ai/ui/behaviors/modal';initModal(); // 事件委托一次绑定,后续 open(id) / close(id) 可编程控制