@data-slot/dialog

中文文档
1.1.3发布于 2026/11/05MITTypeScriptESM + CJS构建来源已验证近 30 天下载 1.3万

Headless modal dialog component for vanilla JavaScript. Accessible, unstyled, tiny.

原始使用文档
文档目录13 节
  1. Installation
  2. Quick Start
  3. API
  4. Initialization
  5. Slots
  6. Data Attributes
  7. Options
  8. Controller
  9. Events
  10. Styling
  11. Keyboard Navigation
  12. Accessibility
  13. License

@data-slot/dialog

Headless modal dialog component for vanilla JavaScript. Accessible, unstyled, tiny.

Installation

npm install @data-slot/dialog

Quick Start

<div data-slot="dialog">
  <button data-slot="dialog-trigger">Open Dialog</button>
  <div data-slot="dialog-overlay" hidden></div>
  <div data-slot="dialog-content" hidden>
    <h2 data-slot="dialog-title">Dialog Title</h2>
    <p data-slot="dialog-description">Dialog description text.</p>
    <button data-slot="dialog-close">Close</button>
  </div>
</div>

<script type="module">
  import { create } from "@data-slot/dialog";
  
  const controllers = create();
</script>

API

Initialization

create(scope?)

Auto-discover and bind all dialog instances in a scope (defaults to document).

import { create } from "@data-slot/dialog";

const controllers = create(); // Returns DialogController[]

createDialog(root, options?)

Create a controller for a specific element.

import { createDialog } from "@data-slot/dialog";

const dialog = createDialog(element, {
  defaultOpen: false,
  closeOnClickOutside: true,
  closeOnEscape: true,
  lockScroll: true,
  onOpenChange: (open) => console.log(open),
});

Slots

Runtime Slots

  • dialog - Root element that manages the open state and receives dialog events.
  • dialog-trigger - Optional button that toggles the dialog.
  • dialog-portal - Optional wrapper moved to document.body while the dialog is open.
  • dialog-overlay - Required backdrop; clicking it dismisses the dialog when outside-click dismissal is enabled.
  • dialog-content - Required modal panel with dialog semantics and focus management.
  • dialog-title - Optional title used for the panel's aria-labelledby.
  • dialog-description - Optional description used for the panel's aria-describedby.
  • dialog-close - Optional button that closes the dialog; multiple close buttons are supported.

Markup

<div data-slot="dialog">
  <button data-slot="dialog-trigger">Open</button>
  <div data-slot="dialog-overlay" hidden></div>
  <div data-slot="dialog-content" role="dialog">
    <h2 data-slot="dialog-title">Title</h2>
    <p data-slot="dialog-description">Description</p>
    <button data-slot="dialog-close">Close</button>
  </div>
</div>

Data Attributes

Options can also be set via data attributes on the root element. JS options take precedence over data attributes.

AttributeTypeDefaultDescription
data-default-openbooleanfalseInitial open state
data-close-on-click-outsidebooleantrueClose when clicking outside content
data-close-on-escapebooleantrueClose when pressing Escape
data-lock-scrollbooleantrueLock body scroll when open
data-alert-dialogbooleanfalseUse alertdialog role for confirmations

Boolean attributes: present or "true" = true, "false" = false, absent = default.

<!-- Disable close on Escape -->
<div data-slot="dialog" data-close-on-escape="false">
  ...
</div>

<!-- Alert dialog that stays open when clicking outside -->
<div data-slot="dialog" data-alert-dialog data-close-on-click-outside="false">
  ...
</div>

Options

OptionTypeDefaultDescription
defaultOpenbooleanfalseInitial open state
closeOnClickOutsidebooleantrueClose when clicking outside content
closeOnEscapebooleantrueClose when pressing Escape
lockScrollbooleantrueLock body scroll when open
alertDialogbooleanfalseUse alertdialog role for confirmations
onOpenChange(open: boolean) => voidundefinedCallback when open state changes

Controller

Method/PropertyDescription
open()Open the dialog
close()Close the dialog
toggle()Toggle the dialog
isOpenCurrent open state (readonly boolean)
destroy()Cleanup all event listeners

Controller Destruction

destroy() permanently disposes the controller and hides any open surface without emitting an additional change event. Repeated destruction is safe; methods on the old controller become no-ops. Create a new controller on the same root to rebind it.

Destruction restores prior focus, falling back to a surviving trigger if the prior target was removed. Destroying an unopened modal does not move focus.

Events

Outbound Events

Listen for changes via custom events:

element.addEventListener("dialog:change", (e) => {
  console.log("Dialog open:", e.detail.open);
});

Inbound Events

Control the dialog via events:

EventDetailDescription
dialog:set{ open: boolean }Set open state programmatically
// Open the dialog
element.dispatchEvent(
  new CustomEvent("dialog:set", { detail: { open: true } })
);

// Close the dialog
element.dispatchEvent(
  new CustomEvent("dialog:set", { detail: { open: false } })
);
Deprecated Shapes

The following shape is deprecated and will be removed in v1.0:

// Deprecated: { value: boolean }
element.dispatchEvent(
  new CustomEvent("dialog:set", { detail: { value: true } })
);

Use { open: boolean } instead.

Styling

Dialog exposes both data-state="open|closed" and popup-style animation hooks:

  • data-open / data-closed on dialog, dialog-portal, dialog-overlay, and dialog-content
  • data-starting-style while opening
  • data-ending-style while closing

Use data-open / data-closed with data-starting-style / data-ending-style for animations:

/* Backdrop */
[data-slot="dialog-overlay"] {
  position: fixed;
  inset: 0;
  background: rgba(0, 0, 0, 0.5);
  opacity: 0;
  transition: opacity 0.2s ease;
}

[data-slot="dialog-overlay"][data-open] {
  opacity: 1;
}

[data-slot="dialog-content"] {
  opacity: 0;
  transform: translate(-50%, -50%) scale(0.95);
  transition:
    opacity 0.2s ease,
    transform 0.2s ease;
}

[data-slot="dialog-content"][data-open] {
  opacity: 1;
  transform: translate(-50%, -50%) scale(1);
}

[data-slot="dialog-overlay"][data-starting-style],
[data-slot="dialog-overlay"][data-ending-style] {
  opacity: 0;
}

[data-slot="dialog-content"][data-starting-style],
[data-slot="dialog-content"][data-ending-style] {
  opacity: 0;
  transform: translate(-50%, -50%) scale(0.95);
}

Stacking is intentionally not hardcoded in JavaScript. Configure z-index in your CSS.
When multiple dialogs are open, data-stack-index and CSS variables are exposed on dialog-overlay and dialog-content:

  • data-stack-index
  • --dialog-stack-index
  • --dialog-overlay-stack-index (overlay)
  • --dialog-content-stack-index (content)

With Tailwind:

<div
  data-slot="dialog-overlay"
  class="fixed inset-0 bg-black/50 opacity-0 transition-opacity duration-200 data-[open]:opacity-100 data-[starting-style]:opacity-0 data-[ending-style]:opacity-0"
></div>
<div
  data-slot="dialog-content"
  class="fixed top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2 bg-white p-6 opacity-0 scale-95 transition-all duration-200 data-[open]:opacity-100 data-[open]:scale-100 data-[starting-style]:opacity-0 data-[starting-style]:scale-95 data-[ending-style]:opacity-0 data-[ending-style]:scale-95"
>
  <!-- Dialog content -->
</div>

Keyboard Navigation

KeyAction
EscapeClose dialog
TabCycle focus within dialog
Shift+TabCycle focus backwards

Accessibility

The component automatically handles:

  • role="dialog" on content
  • aria-modal="true" on content
  • aria-labelledby linked to title
  • aria-describedby linked to description
  • aria-haspopup="dialog" on trigger
  • aria-expanded state on trigger
  • Focus trap within dialog
  • Focus restoration on close

License

MIT

版本与发布记录

@data-slot/dialog 共发布 164 个版本,首次发布于 2026/01/09;过去 12 个月发布了 164 个版本。最新版本附带 npm provenance 构建来源证明,可追溯到公开的 CI 构建记录。

版本发布日期距今
1.1.3latest2026/11/056 天前
1.1.22026/10/1428 天前
1.1.12026/10/051 个月前
1.1.02026/10/021 个月前
1.0.22026/09/271 个月前
1.0.12026/09/261 个月前

关于 @data-slot/dialog 的常见问题

@data-slot/dialog 是什么?

Headless modal dialog component for vanilla JavaScript. Accessible, unstyled, tiny.

如何安装 @data-slot/dialog?

在项目目录运行 npm install @data-slot/dialog,或使用 pnpm add / yarn add / bun add。

@data-slot/dialog 支持 TypeScript 吗?

支持。包内自带 TypeScript 类型声明(package.json 声明了 types 入口),安装后即可获得类型提示,无需再安装 @types 包。

@data-slot/dialog 支持 ESM 还是 CommonJS?

同时提供 ES Module 与 CommonJS 入口,import 和 require() 都可以使用,打包工具会自动选择合适的版本。

@data-slot/dialog 可以商用吗?

@data-slot/dialog 使用 MIT 许可。宽松许可:允许商业使用、修改和再分发,通常只需在分发时保留原版权与许可声明。以上为概括,不构成法律意见,请以许可原文为准。

@data-slot/dialog 的下载量有多少?

根据 npm 官方下载统计,@data-slot/dialog 在 2026/10/12 – 2026/11/10 这 30 天内被下载 12,930 次,日均约 431 次。下载量会把 CI 构建、镜像同步和作为其他包依赖的安装一并计入,适合横向比较热度,不能直接等同于使用人数。

@data-slot/dialog 还在维护吗?

最新版本 1.1.3 发布于 2026/11/05(6 天前);至今共发布 164 个版本,其中过去 12 个月发布了 164 个;首次发布于 2026/01/09。发布频率只是参考信号:功能稳定的工具可能很少需要更新,建议结合源码仓库的 issue 和提交记录判断。