
Security News
Attackers Are Hunting High-Impact Node.js Maintainers in a Coordinated Social Engineering Campaign
Multiple high-impact npm maintainers confirm they have been targeted in the same social engineering campaign that compromised Axios.
English | 中文 | 🎨 CSS Styling System
A lightweight, flexible Vue 3 modal component library built with TypeScript and designed for modern Vue applications.
npm install v-modals
# or
yarn add v-modals
# or
pnpm add v-modals
For detailed usage examples and code demonstrations, please check out our example project:
The example project includes:
The modal component requires CSS styles to display properly. Please refer to the CSS Styling System section at the end of this document for a complete style file example.
| Prop | Type | Default | Description |
|---|---|---|---|
open | boolean | false | Controls modal visibility |
title | string | VNode | - | Modal title |
width | string | number | 520 | Modal width |
centered | boolean | false | Center modal vertically |
closable | boolean | true | Show close button |
closeIcon | string | VNode | - | Custom close icon |
mask | boolean | true | Show background mask |
maskClosable | boolean | true | Close modal when clicking mask |
keyboard | boolean | true | Close modal with ESC key |
destroyOnClose | boolean | false | Destroy modal content when closed |
confirmLoading | boolean | false | Show loading on confirm button |
okText | string | VNode | - | OK button text |
cancelText | string | VNode | - | Cancel button text |
okType | ButtonType | - | OK button type |
okButtonProps | ButtonProps | - | OK button props |
cancelButtonProps | ButtonProps | - | Cancel button props |
zIndex | number | - | Modal z-index |
forceRender | boolean | false | Force render modal content |
getContainer | string | HTMLElement | (() => HTMLElement) | false | - | Container for modal |
maskStyle | CSSProperties | - | Style for mask |
bodyStyle | CSSProperties | - | Style for modal body |
wrapClassName | string | - | Wrapper class name |
style | CSSProperties | string | - | Modal style |
transitionName | string | - | Transition name |
maskTransitionName | string | - | Mask transition name |
focusTriggerAfterClose | boolean | true | Focus trigger after close |
modalRender | (originVNode: VNode) => VNode | - | Custom modal render function |
| Event | Parameters | Description |
|---|---|---|
update:open | (open: boolean) | Emitted when modal visibility changes |
ok | (e: Event) | Emitted when OK button is clicked |
cancel | (e: Event) | Emitted when Cancel button is clicked |
afterClose | () | Emitted after modal is completely closed |
| Slot | Description |
|---|---|
default | Modal content |
title | Custom title content |
footer | Custom footer content |
header | Custom header content |
modalRender | Custom modal wrapper (for draggable functionality) |
| Method | Parameters | Description |
|---|---|---|
Modal.info(options) | ModalOptions | Show info modal |
Modal.success(options) | ModalOptions | Show success modal |
Modal.error(options) | ModalOptions | Show error modal |
Modal.warning(options) | ModalOptions | Show warning modal |
Modal.confirm(options) | ModalOptions | Show confirm modal |
Modal.destroyAll() | - | Destroy all modals |
interface ModalOptions {
title?: string | VNode
content?: string | VNode | (() => VNode)
width?: number | string
centered?: boolean
closable?: boolean
closeIcon?: string | VNode
mask?: boolean
maskClosable?: boolean
keyboard?: boolean
destroyOnClose?: boolean
type?: 'info' | 'success' | 'error' | 'warn' | 'warning' | 'confirm'
okText?: string | VNode
cancelText?: string | VNode
okType?: ButtonType
zIndex?: number
forceRender?: boolean
getContainer?: string | HTMLElement | (() => HTMLElement) | false | null
// Event handlers
onOk?: (...args: any[]) => any
onCancel?: (...args: any[]) => any
afterClose?: () => void
// Advanced options
autoFocusButton?: null | 'ok' | 'cancel'
okButtonProps?: ButtonProps
cancelButtonProps?: ButtonProps
class?: string
style?: CSSProperties | string
wrapClassName?: string
footer?: VNode
icon?: VNode
maskStyle?: CSSProperties
bodyStyle?: CSSProperties
transitionName?: string
maskTransitionName?: string
focusTriggerAfterClose?: boolean
modalRender?: (arg: { originVNode: VNode }) => VNode
mousePosition?: { x: number; y: number } | null
okCancel?: boolean
appContext?: any
}
All programmatic methods return an object with the following methods:
interface ModalInstance {
destroy(): void // Manually destroy the modal
update(options: Partial<ModalOptions>): void // Update modal options
}
The modal component is designed to work with your existing CSS framework. You need to include the modal styles in your project:
/* Import your modal styles */
@import 'path/to/your/modal.css';
The component uses CSS classes that you can customize:
.v-modals-* - Modal container classes.simple-dialog-* - Dialog-specific classes.v-modals-confirm-* - Confirm dialog classesFor advanced usage examples including custom animations, form validation, dynamic content updates, modal chains, and global modal management, please refer to our example project:
confirmLoading is true, the modal automatically disables all close operationsconfirmLoading to false after operations completeonOk and onCancel callbacks are not automatically handledconfirmLoading to manage async operation states!important to force override component internal stylesopen or visible property is correctly setz-index setting is appropriatetransitionName corresponding CSS animation is definedmousePosition is correctly passedmodalRender function is correctly implemented| Property | Type | Default | Description |
|---|---|---|---|
open | boolean | false | Control modal visibility |
title | string | VNode | - | Modal title |
width | string | number | 520 | Modal width |
centered | boolean | false | Vertically center modal |
confirmLoading | boolean | false | Confirm button loading state |
okText | string | VNode | 'OK' | OK button text |
cancelText | string | VNode | 'Cancel' | Cancel button text |
okType | ButtonType | 'primary' | OK button type |
| Property | Type | Description |
|---|---|---|
style | CSSProperties | string | Modal styles |
bodyStyle | CSSProperties | Modal body styles |
maskStyle | CSSProperties | Mask styles |
wrapClassName | string | Wrapper class name |
zIndex | number | Modal z-index |
| Property | Type | Default | Description |
|---|---|---|---|
closable | boolean | true | Show close button |
maskClosable | boolean | true | Close on mask click |
keyboard | boolean | true | Close on ESC key |
destroyOnClose | boolean | false | Destroy content on close |
| Property | Type | Description |
|---|---|---|
modalRender | (arg: { originVNode: VNode }) => VNode | Custom render function (for drag functionality) |
mousePosition | { x: number; y: number } | null | Mouse position for animation start point |
getContainer | string | HTMLElement | (() => HTMLElement) | false | Modal container |
| Event | Parameters | Description |
|---|---|---|
@ok | (e: MouseEvent) | OK button click |
@cancel | (e?: MouseEvent) | Cancel button click or close |
@update:open | (open: boolean) | Visibility state change |
@afterClose | () | Triggered after completely closed |
| Slot | Description |
|---|---|
default | Modal content |
title | Custom title |
footer | Custom footer |
modalRender | Custom wrapper (for drag functionality) |
// Basic methods
Modal.info({ title: 'Info', content: 'Content' })
Modal.success({ title: 'Success', content: 'Operation successful' })
Modal.error({ title: 'Error', content: 'Operation failed' })
Modal.warning({ title: 'Warning', content: 'Warning message' })
Modal.confirm({ title: 'Confirm', content: 'Are you sure?' })
Modal.destroyAll() // Destroy all modals
// useModal Hook
const [modal, contextHolder] = Modal.useModal()
// Returns: [modal methods object, component to render]
const modal = Modal.confirm({...})
modal.destroy() // Destroy modal
modal.update({...}) // Update configuration
interface ModalOptions {
// Basic configuration
title?: string | VNode // Title
content?: string | VNode // Content
width?: string | number // Width
centered?: boolean // Center display
// Button configuration
okText?: string | VNode // OK button text
cancelText?: string | VNode // Cancel button text
okType?: 'primary' | 'danger' // OK button type
// Style configuration
style?: CSSProperties // Custom styles
maskStyle?: CSSProperties // Mask styles
bodyStyle?: CSSProperties // Body styles
// Event handling
onOk?: () => void | Promise<void> // OK callback
onCancel?: () => void // Cancel callback
afterClose?: () => void // After close callback
}
一个轻量级、灵活的 Vue 3 模态框组件库,使用 TypeScript 构建,专为现代 Vue 应用设计。
npm install v-modals
# 或
yarn add v-modals
# 或
pnpm add v-modals
如需查看详细的使用示例和代码演示,请查看我们的示例项目:
👉 查看演示代码
示例项目包括:
open 或 visible 属性是否正确设置z-index 设置是否合适transitionName 对应的 CSS 动画已定义mousePosition 是否正确传递modalRender 函数正确实现以下是所有已验证可用的模态框选项和功能:
open / visible - 显示控制title - 标题设置width - 宽度控制centered - 居中显示closable - 关闭按钮控制closeIcon - 自定义关闭图标mask / maskClosable - 遮罩控制keyboard - 键盘支持confirmLoading - 加载状态(自动禁用关闭操作)okText / cancelText - 按钮文本okType - 按钮类型(primary, danger 等)okButtonProps / cancelButtonProps - 按钮属性style - 自定义样式(如 style="top: 20px")wrapClassName - 包装器类名maskStyle / bodyStyle - 遮罩和主体样式zIndex - 层级控制modalRender - 自定义渲染(拖拽功能)mousePosition - 鼠标位置动画transitionName / maskTransitionName - 自定义动画getContainer - 自定义容器destroyOnClose - 关闭时销毁Modal.info() - 信息对话框Modal.success() - 成功对话框Modal.error() - 错误对话框Modal.warning() / Modal.warn() - 警告对话框Modal.confirm() - 确认对话框Modal.destroyAll() - 销毁所有模态框Modal.useModal() - Hook 版本@ok / @cancel - 按钮点击事件@update:open - 状态更新事件@change - 状态改变事件@after-close - 关闭后事件default - 默认内容插槽title - 标题插槽footer - 底部插槽closeIcon - 关闭图标插槽modalRender - 自定义渲染插槽有关高级用法示例,包括复杂内容创建、异步操作、嵌套模态框、可拖拽模态框等,请参考我们的示例项目:
👉 查看高级示例
| 属性 | 类型 | 默认值 | 描述 |
|---|---|---|---|
open | boolean | false | 控制模态框显示/隐藏 |
title | string | VNode | - | 模态框标题 |
width | string | number | 520 | 模态框宽度 |
centered | boolean | false | 垂直居中显示 |
confirmLoading | boolean | false | 确认按钮加载状态 |
okText | string | VNode | '确定' | 确定按钮文本 |
cancelText | string | VNode | '取消' | 取消按钮文本 |
okType | ButtonType | 'primary' | 确定按钮类型 |
| 属性 | 类型 | 描述 |
|---|---|---|
style | CSSProperties | string | 模态框样式 |
bodyStyle | CSSProperties | 模态框主体样式 |
maskStyle | CSSProperties | 遮罩样式 |
wrapClassName | string | 包装器类名 |
zIndex | number | 模态框层级 |
| 属性 | 类型 | 默认值 | 描述 |
|---|---|---|---|
closable | boolean | true | 显示关闭按钮 |
maskClosable | boolean | true | 点击遮罩层关闭 |
keyboard | boolean | true | ESC 键关闭 |
destroyOnClose | boolean | false | 关闭时销毁内容 |
| 属性 | 类型 | 描述 |
|---|---|---|
modalRender | (arg: { originVNode: VNode }) => VNode | 自定义渲染函数(拖拽功能) |
mousePosition | { x: number; y: number } | null | 鼠标位置动画起始点 |
getContainer | string | HTMLElement | (() => HTMLElement) | false | 模态框容器 |
| 事件 | 参数 | 描述 |
|---|---|---|
@ok | (e: MouseEvent) | 点击确定按钮 |
@cancel | (e?: MouseEvent) | 点击取消按钮或关闭 |
@update:open | (open: boolean) | 显示状态改变 |
@afterClose | () | 完全关闭后触发 |
| 插槽 | 描述 |
|---|---|
default | 模态框内容 |
title | 自定义标题 |
footer | 自定义底部 |
modalRender | 自定义包装器(拖拽功能) |
// useModal Hook
const [modal, contextHolder] = Modal.useModal()
// 返回:[modal方法对象, 需要渲染的组件]
interface ModalOptions {
// 基础配置
title?: string | VNode // 标题
content?: string | VNode // 内容
width?: string | number // 宽度
centered?: boolean // 居中显示
// 按钮配置
okText?: string | VNode // 确定按钮文本
cancelText?: string | VNode // 取消按钮文本
okType?: 'primary' | 'danger' // 确定按钮类型
// 样式配置
style?: CSSProperties // 自定义样式
maskStyle?: CSSProperties // 遮罩样式
bodyStyle?: CSSProperties // 主体样式
// 事件处理
onOk?: () => void | Promise<void> // 确定回调
onCancel?: () => void // 取消回调
afterClose?: () => void // 关闭后回调
}
const modal = Modal.confirm({...})
modal.destroy() // 销毁模态框
modal.update({...}) // 更新配置
Here's a complete modal.css style file example that you can use as a reference to create your own modal styles:
以下是一个完整的 modal.css 样式文件示例,你可以参考这个文件来创建自己的模态框样式:
/* Simple Modal CSS - 独立的 Modal 样式文件 */
/* 这个文件包含所有 Modal 相关的样式,使用 Tailwind CSS 类 */
@import "tailwindcss";
@import "tw-animate-css";
/* Modal 基础样式 */
.simple-modal-root,
.simple-dialog-root {
@apply relative;
}
/* 遮罩层 */
.simple-modal-mask,
.simple-dialog-mask {
@apply fixed inset-0 z-[50] bg-base-300/60 backdrop-blur-sm;
}
/* Modal 容器 */
.simple-modal-wrap,
.simple-dialog-wrap {
@apply fixed inset-0 overflow-auto outline-none z-[50];
-webkit-overflow-scrolling: touch;
}
.simple-modal-wrap-rtl {
direction: rtl;
}
/* 居中布局 */
.simple-modal-wrap.simple-modal-centered,
.simple-dialog-wrap.simple-dialog-centered,
.simple-dialog-wrap.simple-modal-centered {
@apply text-center;
}
.simple-modal-wrap.simple-modal-centered::before,
.simple-dialog-wrap.simple-dialog-centered::before,
.simple-dialog-wrap.simple-modal-centered::before {
@apply inline-block w-0 h-full align-middle;
content: '';
}
.simple-modal-wrap.simple-modal-centered .simple-modal,
.simple-dialog-wrap.simple-dialog-centered .simple-dialog,
.simple-dialog-wrap.simple-modal-centered .simple-dialog {
@apply top-0 inline-block pb-0 text-left align-middle;
}
/* Modal 主体 */
.simple-modal,
.simple-dialog {
position: relative;
top: var(--modal-top, 100px);
/* 使用 CSS 变量,默认 100px */
width: auto;
max-width: calc(100vw - 32px);
margin: 0 auto;
padding-bottom: 1.5rem;
pointer-events: none;
}
/* Modal 内容区域 */
.simple-modal-content,
.simple-dialog-content {
@apply relative bg-base-100 text-base-content border border-base-content/15 rounded-box shadow-2xl p-6 text-base leading-relaxed pointer-events-auto;
}
/* 关闭按钮 */
.simple-modal-close,
.simple-dialog-close {
@apply btn btn-sm btn-ghost btn-circle absolute top-4 right-4 z-10;
}
/* daisyUI 按钮自带 hover 态,这里无需额外样式 */
.simple-modal-close:disabled,
.simple-dialog-close:disabled {
pointer-events: none;
opacity: 0.5;
}
.simple-modal-close-x,
.simple-dialog-close-x {
display: flex;
height: 100%;
width: 100%;
align-items: center;
justify-content: center;
}
.simple-modal-close-icon,
.simple-dialog-close-icon {
height: 1rem;
width: 1rem;
}
/* Modal 头部 */
.simple-modal-header,
.simple-dialog-header {
margin-bottom: 0.5rem;
}
/* Modal 标题 */
.simple-modal-title,
.simple-dialog-title {
@apply m-0 text-lg font-bold leading-snug text-base-content;
}
/* Modal 内容 */
.simple-modal-body,
.simple-dialog-body {
@apply text-base leading-relaxed text-base-content/70;
}
/* Modal 页脚 */
.simple-modal-footer,
.simple-dialog-footer {
@apply flex items-center justify-end gap-2 pt-3;
}
/* Loading 动画 - 确保 spin 动画正确工作 */
@keyframes spin {
from {
transform: rotate(0deg);
}
to {
transform: rotate(360deg);
}
}
.animate-spin {
animation: spin 1s linear infinite;
}
/* 动画效果 - 使用 transition 方式确保兼容性 */
.simple-zoom-enter-active {
transition: all 0.3s cubic-bezier(0.08, 0.82, 0.17, 1);
}
.simple-zoom-leave-active {
transition: all 0.3s cubic-bezier(0.78, 0.14, 0.15, 0.86);
pointer-events: none;
}
.simple-zoom-enter-from,
.simple-zoom-leave-to {
opacity: 0;
transform: scale(0.2);
}
.simple-zoom-enter-to,
.simple-zoom-leave-from {
opacity: 1;
transform: scale(1);
}
.simple-fade-enter-active,
.simple-fade-leave-active {
transition: opacity 0.3s;
}
.simple-fade-enter-from,
.simple-fade-leave-to {
opacity: 0;
}
/* 响应式设计 */
@media (max-width: 767px) {
.simple-modal,
.simple-dialog {
max-width: calc(100vw - 16px);
margin: 8px auto;
}
.simple-modal-centered .simple-modal,
.simple-dialog-centered .simple-dialog {
flex: 1;
}
}
/* 确保 Dialog 组件可见 */
.simple-dialog {
pointer-events: auto;
}
.simple-dialog-content {
pointer-events: auto;
}
/* Confirm Dialog 样式 */
.simple-modal-confirm .simple-modal-header {
display: none;
}
.simple-modal-confirm-body {
display: flex;
flex-wrap: wrap;
align-items: center;
}
/* Confirm Dialog 标题样式 */
.simple-modal-confirm-title {
@apply flex-none block overflow-hidden text-base-content font-semibold text-base leading-snug;
}
.simple-modal-confirm-title+.simple-modal-confirm-content {
margin-top: 0.5rem;
flex: 100%;
max-width: calc(100% - 38px);
}
/* Confirm Dialog 内容样式 */
.simple-modal-confirm-content {
@apply text-base text-base-content/70;
}
/* Confirm Dialog 图标样式 */
.simple-modal-confirm-body>* {
flex: none;
margin-right: 0.75rem;
font-size: 1.125rem;
}
.simple-modal-confirm-body>*+.simple-modal-confirm-title {
flex: 1;
}
.simple-modal-confirm-body>*+.simple-modal-confirm-title+.simple-modal-confirm-content {
margin-left: 34px;
}
/* Confirm Modal 按钮样式 */
.simple-modal-confirm-btns {
@apply flex items-center justify-end gap-2 pt-3;
}
.simple-modal-confirm-btns .simple-btn+.simple-btn {
margin-bottom: 0;
margin-left: 0.5rem;
}
/* 确认框图标颜色 - 直接在 body 元素上应用类型类名 */
.simple-modal-confirm-error>svg {
@apply text-error;
}
.simple-modal-confirm-warning>svg,
.simple-modal-confirm-confirm>svg {
@apply text-warning;
}
.simple-modal-confirm-info>svg {
@apply text-info;
}
.simple-modal-confirm-success>svg {
@apply text-success;
}
CSS Variable Support | CSS 变量支持:
--modal-top: Controls modal distance from top, default 100px | 控制模态框距离顶部的距离,默认 100px--background, --foreground, --muted-foreground, etc.Tailwind CSS Integration | Tailwind CSS 集成:
@apply directive to integrate Tailwind classes | 使用 @apply 指令集成 Tailwind 类Animation System | 动画系统:
simple-zoom: Scale animation effect | 缩放动画效果simple-fade: Fade in/out effect | 淡入淡出效果Copy the CSS code above to your project and save as modal.css
复制上面的 CSS 代码到你的项目中,保存为 modal.css
Import in your main style file | 在你的主样式文件中引入:
@import "./modal.css";
Customize as needed CSS variables and styles 根据需要自定义 CSS 变量和样式
Ensure Tailwind CSS is properly configured (if using) 确保 Tailwind CSS 正确配置(如果使用)
The modal uses the following CSS class structure for customization: 模态框使用以下 CSS 类名结构进行自定义:
.simple-modal-root / .simple-dialog-root - Root container | 根容器.simple-modal-mask / .simple-dialog-mask - Mask layer | 遮罩层.simple-modal-wrap / .simple-dialog-wrap - Modal wrapper | 模态框包装器.simple-modal / .simple-dialog - Modal body | 模态框主体.simple-modal-content / .simple-dialog-content - Content area | 内容区域.simple-modal-header / .simple-dialog-header - Header | 头部.simple-modal-title / .simple-dialog-title - Title | 标题.simple-modal-body / .simple-dialog-body - Body | 主体.simple-modal-footer / .simple-dialog-footer - Footer | 页脚.simple-modal-close / .simple-dialog-close - Close button | 关闭按钮MIT License
Contributions are welcome! Please feel free to submit a Pull Request.
欢迎贡献!请随时提交 Pull Request。
If you encounter any issues while using this library, please submit an Issue or check the example project.
如果您在使用过程中遇到问题,请提交 Issue 或查看示例项目。
This project is inspired by and built upon the excellent work of:
本项目受到以下优秀项目的启发并基于其构建:
Ant Design Vue - A high-quality Vue UI library that provides the foundation and design patterns for this modal component. Their modal implementation served as the primary reference for API design and functionality.
Ant Design - The original React-based design system that established the design principles and interaction patterns that make this modal component intuitive and user-friendly.
We are grateful to the maintainers and contributors of these projects for their outstanding work in creating robust, accessible, and well-designed UI components that benefit the entire frontend development community.
我们感谢 Ant Design Vue 和 Ant Design 的维护者和贡献者们,感谢他们在创建强大、可访问且设计精良的 UI 组件方面所做的杰出工作,这些工作使整个前端开发社区受益。
Special thanks to:
特别感谢:
This modal component aims to provide a lightweight, framework-agnostic solution while maintaining the familiar API and behavior patterns that developers love from Ant Design Vue.
这个模态框组件旨在提供一个轻量级、框架无关的解决方案,同时保持开发者喜爱的 Ant Design Vue 熟悉的 API 和行为模式。
FAQs
A simple Vue 3 modal component with internationalization support
We found that v-modals demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Security News
Multiple high-impact npm maintainers confirm they have been targeted in the same social engineering campaign that compromised Axios.

Security News
Axios compromise traced to social engineering, showing how attacks on maintainers can bypass controls and expose the broader software supply chain.

Security News
Node.js has paused its bug bounty program after funding ended, removing payouts for vulnerability reports but keeping its security process unchanged.