--- type: ai-agent-documentation version: 2.0 component: Dialog status: stable audience: ai-coding-agents-only human-readable: false category: overlay framework-support: - vanilla: true - react: true - vue: true - angular: true - svelte: true --- # Component: Dialog DEFINITION: The Dialog component provides accessible, modal overlays for user interaction, such as confirmations, forms, or alerts. It traps focus and manages keyboard interactions. ## Installation ```bash npm install @pm7/core ``` ### CSS & JavaScript Import REQUIRED: Import both the CSS and the main JavaScript file. ```javascript // ES modules import '@pm7/core/dist/pm7.css'; import '@pm7/core'; // Imports and initializes all components, including global dialog functions // HTML ``` ## Required Structure The Dialog component requires a main container with a unique `data-pm7-dialog` ID, and three distinct sections marked by `data-pm7-header`, `data-pm7-body`, and `data-pm7-footer` attributes. ```html
Dialog Title

Dialog content goes here.

``` ### Structural Rules - **ALWAYS**: The main dialog container MUST have a unique `data-pm7-dialog="your-id"` attribute. - **ALWAYS**: A dialog MUST contain exactly one `div` with `data-pm7-header`, one `div` with `data-pm7-body`, and one `div` with `data-pm7-footer`. - **ALWAYS**: Use `window.openDialog('your-id')` to open the dialog and `window.closeDialog('your-id')` to close it. - **NEVER**: Manually apply `display: none` or `display: block` to control dialog visibility. ## JavaScript API ### Initialization Dialogs are automatically initialized when the `pm7.js` script is loaded and they are present in the DOM. For dynamically added dialogs, `window.PM7.init()` must be called. ### Global Functions ```javascript // Available globally after pm7.js is loaded window.openDialog(id: string); window.closeDialog(id: string); window.closeAllDialogs(); ``` | Function | Parameters | Return Type | Description | |---|---|---|---| | `window.openDialog` | `id: string` | `void` | Opens the dialog with the specified `data-pm7-dialog` ID. | | `window.closeDialog` | `id: string` | `void` | Closes the dialog with the specified `data-pm7-dialog` ID. | | `window.closeAllDialogs` | `(none)` | `void` | Closes all currently open dialogs. | ### Events | Event | When | Detail | Bubbles | |---|---|---|---|---| | `pm7:dialog:open` | After a dialog opens | `{ dialogId: string }` | YES | | `pm7:dialog:close` | After a dialog closes | `{ dialogId: string }` | YES | ## Attributes See /docs/ATTRIBUTES.md for cross-component attribute relationships. | Attribute | Component(s) | Values | Required | Effect | |---|---|---|---|---| | `data-pm7-dialog` | Dialog | unique string ID | YES | Initializes Dialog component; used for `openDialog`/`closeDialog`. | | `data-pm7-dialog-size` | Dialog | `sm`, `md`, `lg`, `xl`, `full` | NO | Sets the width of the dialog. | | `data-pm7-show-close` | Dialog | presence | NO | Displays a close (X) button in the dialog header. | | `data-pm7-no-escape` | Dialog | presence | NO | Prevents closing the dialog with the ESC key. | | `data-pm7-no-overlay-close` | Dialog | presence | NO | Prevents closing the dialog by clicking the overlay. | | `data-pm7-header` | Dialog | presence | YES | Marks the header section of a dialog. | | `data-pm7-body` | Dialog | presence | YES | Marks the body section of a dialog. | | `data-pm7-footer` | Dialog | presence | YES | Marks the footer section of a dialog. | | `data-state` | Dialog | `open`, `closed` | AUTO | Managed by JS to reflect component's open/closed state. | | `aria-modal` | Dialog | `true` | AUTO | Indicates that an element is a modal dialog and disables interaction with other content. | | `role` | Dialog | `dialog` | AUTO | Defines the purpose or nature of an element. | ## CSS Classes | Class | Auto-Applied | Purpose | |---|---|---| | `.pm7-dialog` | YES | Base styling for the dialog content. | | `.pm7-dialog-overlay` | YES | Styles the backdrop behind the dialog. | | `.pm7-dialog-container` | YES | Positions the dialog centrally. | | `.pm7-dialog-header` | YES | Styles the header section. | | `.pm7-dialog-body` | YES | Styles the main content area. | | `.pm7-dialog-footer` | YES | Styles the action button area. | | `.pm7-dialog-close` | YES | Styles the auto-generated close button (if `data-pm7-show-close` is used). | ## Patterns ### Pattern: Basic Confirmation Dialog ```html
Confirm Deletion

Are you sure you want to delete this item? This action cannot be undone.

``` ### Pattern: Dialog with Form Input ```html
Edit Your Profile
``` ### Pattern: Alert Dialog (Non-dismissible by ESC/Overlay) ```html
Important Alert

Your session has expired. Please log in again.

``` ## Anti-Patterns ### NEVER: Nest dialogs ```html
...
Nesting dialogs breaks focus management, accessibility, and can lead to unexpected visual stacking issues. // Use separate dialogs and open them sequentially if needed. // For example, close the first dialog before opening the second. ``` ### NEVER: Use duplicate `data-pm7-dialog` IDs ```html
...
...
Dialog functions (`openDialog`, `closeDialog`) rely on unique IDs to target specific dialogs. Duplicates will cause unpredictable behavior.
...
...
``` ### NEVER: Conditionally render dialogs without `null` check in frameworks ```jsx // NEVER (React example) function MyDialog({ isOpen }) { // This will cause issues as the dialog element is always in the DOM return (
...
); } // BECAUSE PM7 Dialogs are designed to be added/removed from the DOM. Simply hiding them with CSS breaks their lifecycle and focus management. // INSTEAD function MyDialog({ isOpen }) { if (!isOpen) return null; // CRITICAL: Render null when not open return (
...
); } ``` ## React Integration > **📚 Framework Integration Guide**: For Vue, Angular, and other framework integrations, see the comprehensive [Framework Integration Guide](https://raw.githubusercontent.com/patrickmast/pm7-ui/main/README-Framework-Integration.md) ### ⚠️ CRITICAL: Event Handling in React PM7-UI dialogs require special handling in React due to event system conflicts: 1. **NEVER use React event handlers (onClick) on PM7 internal elements** - React's synthetic events conflict with PM7's event handling - Use `dangerouslySetInnerHTML` with lowercase `onclick` attributes instead 2. **The onclick vs onClick Problem** - React filters out lowercase HTML attributes like `onclick` - Only PascalCase attributes like `onClick` are passed through - Solution: Use `dangerouslySetInnerHTML` for buttons in dialogs 3. **Use Global Functions for Event Handling** ```jsx // Define global functions in your app initialization useEffect(() => { window.handleDialogCancel = () => { window.closeDialog('my-dialog'); // Update your React state here }; }, []); ``` ### Complete React Example ```jsx function App() { const [showDialog, setShowDialog] = useState(false); const [dialogContent, setDialogContent] = useState(''); // Initialize PM7 and global functions useEffect(() => { window.PM7?.initFramework(); // Global functions for dialog buttons window.handleDialogCancel = () => { window.closeDialog('my-dialog'); setShowDialog(false); }; window.handleDialogConfirm = () => { window.closeDialog('my-dialog'); setShowDialog(false); // Process the dialog result }; }, []); // Manage dialog visibility useEffect(() => { if (showDialog) { window.openDialog('my-dialog'); } }, [showDialog]); return ( <> {/* Dialog must always be rendered, PM7 controls visibility */}
Dialog Title
{dialogContent}
Cancel ` }} />
); } ``` ### Key Points for React: - Always render the dialog in the DOM (PM7 handles visibility) - Use `dangerouslySetInnerHTML` for footer buttons with `onclick` - Define global functions for event handling - Synchronize React state with PM7 dialog state - See [Framework Integration Guide](../../../../../../README-Framework-Integration.md) for more details ## Rules ### ALWAYS - **ALWAYS**: Provide a unique `data-pm7-dialog` ID for every dialog. - **ALWAYS**: Include `data-pm7-header`, `data-pm7-body`, and `data-pm7-footer` sections. - **ALWAYS**: Use `window.openDialog()` and `window.closeDialog()` to control dialog visibility. - **ALWAYS**: In frameworks like React/Vue, conditionally render the dialog component (return `null` when not open) to ensure proper DOM management. ### NEVER - **NEVER**: Nest one dialog inside another. - **NEVER**: Use duplicate `data-pm7-dialog` IDs. - **NEVER**: Manually control dialog visibility using CSS `display` properties. - **NEVER**: Forget to call `window.PM7.init()` if you add dialogs to the DOM dynamically after initial page load. - **NEVER**: Use React onClick handlers on PM7 dialog buttons (use `dangerouslySetInnerHTML` with `onclick` instead). ## CSS Variables ### Component-Specific Variables Dialog does not define its own CSS variables. All styling is controlled through global PM7 design tokens. ### Required Global Variables | Variable | Light Mode | Dark Mode | Usage in Dialog | |----------|------------|-----------|-----------------| | `--pm7-background` | `#ffffff` | `#121212` | Dialog content background | | `--pm7-foreground` | `#000000` | `#e0e0e0` | Dialog title and body text | | `--pm7-muted` | `#f5f5f5` | `#2d2d2d` | Footer background, close button hover | | `--pm7-muted-foreground` | `#333333` | `#e6e6e6` | Dialog description text, close button icon | | `--pm7-border` | `#e0e0e0` | `#444` | Dialog border, footer separator | | `--pm7-radius-lg` | `0.75rem` | `0.75rem` | Dialog border radius | | `--pm7-ring` | `#1C86EF` | `#3b9eff` | Focus ring for close button | | `--pm7-spacing-4` | `1rem` | `1rem` | Close button position, mobile padding | | `--pm7-spacing-6` | `1.5rem` | `1.5rem` | Header/body padding | | `--pm7-error` | `#ef4444` | `#ef4444` | Alert dialog header background | | `--pm7-error-foreground` | `#ffffff` | `#ffffff` | Alert dialog header text | | `--pm7-success` | `#22c55e` | `#22c55e` | Success dialog header background | | `--pm7-success-foreground` | `#ffffff` | `#ffffff` | Success dialog header text | | `--pm7-primary` | `#1C86EF` | `#3b9eff` | Loading spinner color | ### Customization Example ```css /* Custom branded dialog */ .my-app { --pm7-background: #f8f9fa; --pm7-foreground: #212529; --pm7-muted: #e9ecef; --pm7-border: #dee2e6; --pm7-radius-lg: 1rem; } /* Dark mode overrides */ .my-app.dark { --pm7-background: #1a1a1a; --pm7-foreground: #f8f9fa; --pm7-muted: #2d2d2d; --pm7-border: #495057; } ``` ## Cross-Component Dependencies ### Works With - **Button**: Often used in dialog footers for actions (Save, Cancel, Delete) - **Menu**: Can trigger dialogs from menu items via `onclick` handlers - **Toast**: Show toast notifications after dialog actions complete - **Input**: Form elements frequently used in dialog bodies ### Conflicts With - **Tooltip**: NEVER use tooltips on dialog triggers or inside dialogs (focus management conflicts) - **Sidebar**: Both use modal overlays - avoid opening simultaneously ## Accessibility - **Focus**: Dialogs implement a focus trap, ensuring keyboard focus remains within the open dialog. - **Keyboard**: `Escape` key closes the dialog (unless `data-pm7-no-escape` is present). `Tab` and `Shift+Tab` navigate within the dialog. - **ARIA**: Dialogs automatically apply `role="dialog"`, `aria-modal="true"`, and manage `aria-labelledby` and `aria-describedby` if a title/description is present. - **Screen reader**: Fully accessible to screen readers, announcing the modal nature and content. ## Complete Example: User Profile Management SCENARIO: A user can view and edit their profile details through a dialog. ```html
User Profile
```