
Syncfusion React Popups
- 395 installs
- 3 repo stars
- Updated July 28, 2026
- syncfusion/react-ui-components-skills
Use syncfusion-react-popups for development tasks
About
syncfusion-react-popups: A skill for development. This provides functionality for development workflows.
- syncfusion-react-popups
Syncfusion React Popups by the numbers
- 395 all-time installs (skills.sh)
- +53 installs in the week ending Aug 5, 2026 (Skillselion tracking)
- Ranked #1,095 of 4,347 Backend & APIs skills by installs in the Skillselion catalog
- Data as of Aug 5, 2026 (Skillselion catalog sync)
npx skills add https://github.com/syncfusion/react-ui-components-skills --skill syncfusion-react-popupsAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 395 |
|---|---|
| repo stars | ★ 3 |
| Last updated | July 28, 2026 |
| Repository | syncfusion/react-ui-components-skills ↗ |
What it does
Use syncfusion-react-popups for development tasks
Files
Syncfusion React Popups Component
Implementing Syncfusion React Dialog Component
The DialogComponent displays content in a floating window with support for modal and modeless modes, custom positioning, dragging, resizing, animations, templating, and comprehensive accessibility features.
Component Overview
DialogComponent Features:
- Modal/Modeless modes: Control parent interaction blocking
- 9 preset positions + custom X/Y: Flexible placement
- Dragging: Header-based drag and drop (allowDragging)
- Resizing: Diagonal resize grip (enableResize)
- Templating: Custom header, content, footer
- Animations: 16 effects (Fade, Zoom, Flip, Slide, FadeZoom, etc.)
- Buttons: Built-in action buttons with click handlers
- Events: open, close, beforeOpen, beforeClose, drag, dragStart, dragStop, resize events
- Keyboard Navigation: Tab, Escape (closeOnEscape), Enter
- WCAG 2.2 Accessibility: ARIA roles, focus management
- Localization: 20+ locales via locale property
- RTL Support: Right-to-left rendering
Documentation & Navigation Guide
Getting Started
📄 Read: references/getting-started.md
- Installation (
@syncfusion/ej2-react-popups) - CSS/theme imports (material, bootstrap, tailwind)
- Basic DialogComponent JSX structure
- show()/hide() methods and refs
- Functional component patterns with hooks
- Initial visibility with visible prop
Modal vs Modeless
📄 Read: references/modal-vs-modeless.md
- isModal boolean property (true/false)
- Modal overlay behavior and parent blocking
- Modeless floating behavior
- Focus management differences
- When to choose each mode
- Side-by-side comparisons
Positioning and Dragging
📄 Read: references/positioning-and-dragging.md
- position object (X: 'center'|'left'|'right'|number, Y: 'top'|'center'|'bottom'|number)
- 9 preset position combinations
- Custom pixel-based positioning
- allowDragging boolean property
- enableResize and resizeHandles configuration
- Target element constraints with target prop
Templates and Content
📄 Read: references/templates-and-content.md
- content property (string, HTML, JSX function)
- header property (text or template)
- footerTemplate (custom footer JSX)
- Dynamic content updates
- HTML sanitization (enableHtmlSanitizer)
- Styling content and edge cases
Buttons and Actions
📄 Read: references/buttons-and-actions.md
- buttons array with ButtonPropsModel[]
- ButtonPropsModel structure (buttonModel, click, isFlat, type)
- buttonModel properties (content, isPrimary, cssClass)
- Click event handlers
- Styling buttons with cssClass
- Button types (Button, Submit, Reset)
Animation Effects
📄 Read: references/animation-effects.md
- AnimationSettingsModel (effect, duration, delay)
- 16 animation effects (Fade, FadeZoom, FlipLeftDown, FlipLeftUp, etc.)
- Duration in milliseconds
- Delay before animation starts
- Disable animations (effect: 'None')
- Performance considerations
Localization and Accessibility
📄 Read: references/localization-and-accessibility.md
- locale property for culture/language
- WCAG 2.2 compliance
- Keyboard navigation (Tab, Enter, Escape)
- closeOnEscape behavior control
- ARIA roles and attributes
- Screen reader support
- RTL support with enableRtl
- Focus management patterns
Advanced Patterns
📄 Read: references/advanced-patterns.md
- Events: open, close, beforeOpen, beforeClose, drag, dragStart, dragStop, resizeStart, resizeStop, resizing
- Nested and stacked dialogs
- Forms with validation
- AJAX content loading
- Prevent close logic (beforeClose event)
- Full-screen dialogs
- HTML sanitization and security
- CSS classes and z-index management
- Enable persistence (enablePersistence)
- Common edge cases and troubleshooting
API Reference (Complete)
📄 Read: references/api-reference.md
- All 24 DialogModel properties with types and defaults
- All 11 events with event arguments
- Methods: show(), hide(), refresh(), destroy()
- ButtonPropsModel structure (buttonModel, click, isFlat, type)
- AnimationSettingsModel with all 16 effects
- Types and enumerations
- Quick reference patterns
Quick Start Example
⚠️ Dependency Alignment: All @syncfusion/ej2-* packages must be on the same major version to avoid peer-dependency conflicts and supply-chain mismatches. Install them together:```
npm install @syncfusion/ej2-react-popups @syncfusion/ej2-base @syncfusion/ej2-buttons @syncfusion/ej2-popups
```
Basic Modal Dialog:
import React, { useRef, useState } from 'react';
import { DialogComponent } from '@syncfusion/ej2-react-popups';
import '@syncfusion/ej2-base/styles/material.css';
import '@syncfusion/ej2-buttons/styles/material.css';
import '@syncfusion/ej2-popups/styles/material.css';
export default function App() {
const dialogRef = useRef(null);
const [isOpen, setIsOpen] = useState(false);
const handleOpen = () => {
dialogRef.current?.show();
setIsOpen(true);
};
const handleClose = () => {
dialogRef.current?.hide();
setIsOpen(false);
};
const buttons = [
{
buttonModel: {
content: 'OK',
cssClass: 'e-flat',
isPrimary: true,
},
click: handleClose,
},
{
buttonModel: {
content: 'Cancel',
cssClass: 'e-flat',
},
click: handleClose,
},
];
return (
<div id="dialog-target" style={{ position: 'relative', width: '100%', minHeight: '400px' }}>
<button onClick={handleOpen} className="e-control e-btn e-primary">
Open Dialog
</button>
<DialogComponent
ref={dialogRef}
header="Confirm Action"
buttons={buttons}
showCloseIcon={true}
target="#dialog-target"
width="400px"
isModal={true}
visible={false}
>
<p>Are you sure you want to proceed with this action?</p>
</DialogComponent>
</div>
);
}Common Patterns
Pattern 1: Confirmation Dialog
Delete action with confirmation buttons:
const buttons = [
{
buttonModel: { content: 'Delete', cssClass: 'e-flat e-danger', isPrimary: true },
click: () => { performDelete(); dialogRef.current?.hide(); }
},
{
buttonModel: { content: 'Cancel', cssClass: 'e-flat' },
click: () => dialogRef.current?.hide()
}
];Pattern 2: Form Dialog
Dialog with form inputs and validation:
<DialogComponent header="Edit Profile" buttons={buttons} isModal={true} width="500px">
<div style={{ padding: '16px' }}>
<input type="text" placeholder="Name" className="form-control" />
<input type="email" placeholder="Email" className="form-control" />
<textarea placeholder="Bio" className="form-control"></textarea>
</div>
</DialogComponent>Pattern 3: Centered Dialog
Position dialog in center of screen:
<DialogComponent
header="Alert"
position={{ X: 'center', Y: 'center' }}
isModal={true}
showCloseIcon={true}
width="350px"
>
This dialog is centered on the screen.
</DialogComponent>Pattern 4: Draggable Floating Panel
Non-modal, draggable properties panel:
<DialogComponent
header="Properties"
isModal={false}
allowDragging={true}
position={{ X: 200, Y: 150 }}
width="300px"
enableResize={true}
resizeHandles={['All']}
showCloseIcon={true}
>
Drag me around! I don't block the page.
</DialogComponent>Pattern 5: Animated Dialog
Dialog with Zoom animation:
<DialogComponent
header="Welcome"
animationSettings={{ effect: 'Zoom', duration: 400, delay: 0 }}
isModal={true}
position={{ X: 'center', Y: 'center' }}
width="400px"
>
This dialog zooms in smoothly!
</DialogComponent>Pattern 6: Custom Footer Template
Custom footer instead of buttons:
<DialogComponent
header="Custom Footer"
isModal={true}
footerTemplate={
<div style={{ padding: '12px', textAlign: 'right' }}>
<button className="e-control e-btn e-primary" style={{ marginRight: '8px' }}>
Save
</button>
<button className="e-control e-btn">Cancel</button>
</div>
}
>
Dialog content with custom footer.
</DialogComponent>Pattern 7: Nested Dialogs
Parent dialog containing child dialog:
const childDialogRef = useRef(null);
<DialogComponent header="Parent" isModal={true} width="400px">
<button onClick={() => childDialogRef.current?.show()} className="e-control e-btn">
Open Child Dialog
</button>
<DialogComponent
ref={childDialogRef}
header="Child"
isModal={true}
width="300px"
visible={false}
>
Nested dialog content
</DialogComponent>
</DialogComponent>Key Props (DialogModel)
| Prop | Type | Description | Default | When to Use |
|---|---|---|---|---|
isModal | boolean | Enable modal mode (blocks parent interaction) | false | Confirmations, alerts, critical actions |
visible | boolean | Initial visibility state | false | Control initial dialog display |
header | string \ | JSX | Dialog header/title | - |
content | string \ | HTML \ | JSX | Dialog body content |
buttons | ButtonPropsModel[] | Action buttons in footer | - | For OK/Cancel, action confirmations |
footerTemplate | JSX | Custom footer content | - | When buttons prop doesn't fit |
showCloseIcon | boolean | Show close button in header | false | Allow users to dismiss |
position | PositionData | X/Y positioning (center, top, etc.) | { X: 'center', Y: 'center' } | Custom placement |
allowDragging | boolean | Enable drag functionality | false | Movable dialogs, floating panels |
enableResize | boolean | Enable resize with grip | false | Resizable dialogs |
resizeHandles | ResizeDirections[] | Which edges/corners resize | ['All'] | Control resize behavior |
width | string \ | number | Dialog width | '330px' |
height | string \ | number | Dialog height | 'auto' |
minHeight | string \ | number | Minimum height | - |
animationSettings | AnimationSettingsModel | Animation effect/duration/delay | - | Smooth open/close transitions |
closeOnEscape | boolean | Close on Escape key press | true | Keyboard navigation |
target | string (selector) | Container element | document.body | Modal positioning |
enableHtmlSanitizer | boolean | Sanitize HTML content | true | Security (prevent XSS) |
cssClass | string | Custom CSS classes | - | Styling and theming |
enableRtl | boolean | Right-to-left rendering | false | RTL languages |
locale | string | Culture/language code | 'en-US' | Localization |
zIndex | number | Stack order | - | Manage overlapping dialogs |
enablePersistence | boolean | Persist state on reload | false | Remember size/position |
Common Use Cases
1. Confirmation Dialogs - Confirm delete, submit, or critical actions before proceeding 2. Alert/Info Popups - Display system messages, warnings, or notifications 3. Form Dialogs - Edit profiles, settings, or create new records in modal forms 4. Input Prompts - Collect user input for specific actions (e.g., "Enter file name") 5. Properties Panels - Draggable, non-modal panels for settings or properties 6. Multi-Step Workflows - Nested dialogs for step-by-step processes 7. Loading/Processing - Show progress indicators or loading states 8. Help/Documentation - Contextual help, tips, or tutorial overlays 9. Image Galleries - Lightbox dialogs for images or media previews 10. Settings/Preferences - Organize application settings in tabbed dialogs
---
Next: Choose a reference based on what you need to implement. All references include working code examples, best practices, and troubleshooting guidance.
Implementing Syncfusion React Predefined Dialog Component
Table of Contents
Key Concept
Syncfusion Predefined Dialogs are not component-based (<ejs-dialog>). They are opened imperatively via the `DialogUtility` utility class:
| Dialog Type | Method |
|---|---|
| Alert | DialogUtility.alert({ ... }) |
| Confirm | DialogUtility.confirm({ ... }) |
| Prompt (input) | DialogUtility.confirm({ content: '<input .../>', ... }) |
Import: import { DialogUtility } from '@syncfusion/ej2-react-popups';
---
Quick Start
import { ButtonComponent } from '@syncfusion/ej2-react-buttons';
import { DialogUtility } from '@syncfusion/ej2-react-popups';
import * as React from 'react';
function App() {
function showAlert() {
DialogUtility.alert({
title: 'Low Battery',
width: '250px',
content: '10% of battery remaining',
});
}
return <ButtonComponent cssClass="e-danger" onClick={showAlert}>Alert</ButtonComponent>;
}
export default App;---
Documentation Guide
Getting Started
📄 Read: references/getting-started.md
- Installation (
@syncfusion/ej2-react-popups) - CSS imports
- Alert, Confirm, and Prompt minimal examples
- Functional and class component patterns
Animation
📄 Read: references/animation.md
animationSettingsproperty witheffect,duration,delay- Alert / Confirm / Prompt animation examples
Draggable
📄 Read: references/draggable.md
isDraggableboolean property- Alert / Confirm / Prompt drag examples
Position
📄 Read: references/position.md
positionproperty:{ X, Y }—left|center|right/top|center|bottomor numeric offset- Alert / Confirm / Prompt position examples
Dimension
📄 Read: references/dimension.md
widthandheightpropertiescssClassfor max-width / min-width constraints- Alert / Confirm / Prompt dimension examples
Customization
📄 Read: references/customization.md
okButton/cancelButton— customtext,icon,clickhandlershowCloseIconandcloseOnEscape- Custom
contentfor prompt dialogs
API Reference
📄 Read: references/api.md
- Full
DialogUtility.alert()/confirm()option properties - All supported fields:
title,content,width,height,position,animationSettings,isDraggable,okButton,cancelButton,showCloseIcon,closeOnEscape,cssClass
---
Common Patterns
Alert with OK callback:
const dialogObj = DialogUtility.alert({
title: 'Info',
content: 'Operation complete.',
okButton: { click: () => { dialogObj.hide(); } }
});Confirm with Yes / No:
const dialogObj = DialogUtility.confirm({
title: 'Delete?',
content: 'Are you sure?',
width: '300px',
okButton: { text: 'Yes', click: () => { dialogObj.hide(); /* do delete */ } },
cancelButton: { text: 'No', click: () => { dialogObj.hide(); } }
});Prompt (input capture):
const dialogObj = DialogUtility.confirm({
title: 'Enter Name',
content: '<p>Your name:</p><input id="nameInput" class="e-input" placeholder="Type here..." />',
width: '300px',
okButton: {
text: 'Submit',
click: () => {
const val = (document.getElementById('nameInput') as HTMLInputElement).value;
dialogObj.hide();
}
},
cancelButton: { click: () => dialogObj.hide() }
});Implementing Syncfusion React Tooltip
A comprehensive skill for implementing the Syncfusion React TooltipComponent — covering setup, content strategies, positioning, open modes, animation, customization, accessibility, and advanced how-to patterns.
Package: @syncfusion/ej2-react-popups Import: import { TooltipComponent } from '@syncfusion/ej2-react-popups';
Quick Start
npm install @syncfusion/ej2-react-popups --save/* src/App.css */
@import "../node_modules/@syncfusion/ej2-base/styles/tailwind3.css";
@import "../node_modules/@syncfusion/ej2-react-popups/styles/tailwind3.css";import * as React from 'react';
import { TooltipComponent } from '@syncfusion/ej2-react-popups';
import './App.css';
function App() {
return (
<TooltipComponent content="Tooltip Content" position="TopCenter">
<button className="e-btn">Show Tooltip</button>
</TooltipComponent>
);
}
export default App;Navigation Guide
Getting Started & Setup
📄 Read: references/getting-started.md
- Installation and CSS imports
- Basic tooltip on a single element
- Tooltip on multiple targets within a container (
targetprop) - Using
titleattribute as fallback content - Running the application
Content
📄 Read: references/content.md
- Plain string content
- Template content (JSX function)
- Dynamic content loaded via Fetch/Ajax (
beforeRenderevent) - HTML content (iframe, embedded elements)
- Updating content programmatically with
dataBind()
Positioning
📄 Read: references/position.md
- 12 static positions (
TopLeft,TopCenter,TopRight,BottomLeft,BottomCenter,BottomRight,LeftTop,LeftCenter,LeftBottom,RightTop,RightCenter,RightBottom) - Tip pointer show/hide (
showTipPointer) and positioning (tipPointerPosition: Auto, Start, Middle, End) - Dynamic positioning with
refresh()method (draggable targets) - Mouse trailing (
mouseTrail) - Offset values (
offsetX,offsetY) - Collision handling (auto-flip behavior,
windowCollision)
Open Modes
📄 Read: references/open-mode.md
Auto,Hover,Click,Focus,Custommodes viaopensOn- Combining multiple modes (
opensOn="Hover Click") - Sticky mode (
isSticky) — close button appears - Open/close delay (
openDelay,closeDelay) - Custom open mode with
open()andclose()methods - Mobile behavior (tap-and-hold)
Animation
📄 Read: references/animation.md
animationproperty (open/closeAnimationModel)- All 15 available animation effects (FadeIn, ZoomIn, FlipX/Y, etc.)
- Custom duration and delay
- Animating via
open()andclose()methods programmatically - Transition effect using
beforeRender+ CSS transitions
Customization
📄 Read: references/customization.md
cssClassfor custom themes and styles- Tip pointer size, background, and border customization
- Full tooltip appearance (background, opacity, font)
- Curved tip and bubble tip arrow patterns
- Dimension control (
width,height) and scroll mode - RTL support (
enableRtl)
How-To Patterns
📄 Read: references/how-to.md
- Tooltip on multiple targets (dynamic content per target)
- Tooltip on disabled elements
- Enabling/disabling tooltip with
destroy()andrender() - Displaying tooltip on SVG and Canvas elements
- Embedding iframes or HTML elements in tooltip content
- Custom open modes (double-click, right-click)
Accessibility
📄 Read: references/accessibility.md
- WCAG 2.2 and Section 508 compliance
- WAI-ARIA attributes (
role="tooltip",aria-describedby,aria-hidden) - Keyboard shortcuts (Escape, Tab)
- Screen reader behavior
API Reference
📄 Read: references/api.md
- All properties, methods, and events with types and defaults
TooltipAnimationSettings,TooltipEventArgstypesPositionandTipPointerPositionenum values
Common Patterns
Tooltip on a Button
<TooltipComponent content="Submit the form" position="TopCenter">
<button className="e-btn e-primary">Submit</button>
</TooltipComponent>Multi-Target Tooltip in a Container
// Single TooltipComponent handles all .e-info targets;
// each uses its own `title` attribute as content
<TooltipComponent target=".e-info" position="RightCenter">
<form>
<input className="e-info" type="text" title="Enter your name" />
<input className="e-info" type="email" title="Enter a valid email" />
</form>
</TooltipComponent>Click-Triggered Sticky Tooltip
<TooltipComponent
content="Click the × to close me"
opensOn="Click"
isSticky={true}
position="BottomCenter"
>
<button className="e-btn">Click Me</button>
</TooltipComponent>Programmatic Open/Close
import * as React from 'react';
import { TooltipComponent } from '@syncfusion/ej2-react-popups';
function App() {
let tooltipRef: TooltipComponent;
const target = React.useRef<HTMLButtonElement>(null);
return (
<TooltipComponent
ref={t => (tooltipRef = t)}
content="Tooltip opened programmatically"
opensOn="Custom"
>
<button
ref={target}
className="e-btn"
onClick={() => {
if (target.current.getAttribute('data-tooltip-id')) {
tooltipRef.close();
} else {
tooltipRef.open(target.current);
}
}}
>
Toggle Tooltip
</button>
</TooltipComponent>
);
}Mouse-Trailing Tooltip
<TooltipComponent
content="Following your mouse!"
mouseTrail={true}
showTipPointer={false}
>
<div style={{ width: '200px', height: '100px', background: '#eee' }}>
Hover over me
</div>
</TooltipComponent>Key Props at a Glance
| Prop | Type | Default | Purpose |
|---|---|---|---|
content | `string \ | HTMLElement \ | Function` |
target | string | — | CSS selector for multi-target mode |
position | Position | 'TopCenter' | 12 placement values |
opensOn | string | 'Auto' | Hover / Click / Focus / Custom |
isSticky | boolean | false | Keep visible until user closes |
mouseTrail | boolean | false | Follow mouse cursor |
showTipPointer | boolean | true | Show/hide arrow tip |
tipPointerPosition | TipPointerPosition | 'Auto' | Auto / Start / Middle / End |
openDelay | number | 0 | ms delay before opening |
closeDelay | number | 0 | ms delay before closing |
offsetX / offsetY | number | 0 | Distance from target (px) |
width / height | `string \ | number` | 'auto' |
cssClass | string | null | Custom CSS class |
animation | AnimationModel | FadeIn/FadeOut 150ms | Open/close animation |
enableRtl | boolean | false | Right-to-left rendering |
enableHtmlSanitizer | boolean | true | Sanitize HTML content |
container | `string \ | HTMLElement` | body |
windowCollision | boolean | false | Collision vs viewport |
Advanced Patterns
Table of Contents
- Nested Dialogs
- Dialog with Forms
- AJAX Content Loading
- RTL Support
- Prevent Closing on Backdrop Click
- Full-Screen Dialogs
- Utility Functions
- Common Gotchas
- Performance Tips
- Migration from EJ1
Nested Dialogs
Create child dialogs within parent dialogs:
import React, { useRef } from 'react';
import { DialogComponent } from '@syncfusion/ej2-react-popups';
import './App.css';
export function NestedDialogs() {
const parentRef = useRef(null);
const childRef = useRef(null);
const parentButtons = [
{
buttonModel: { content: 'Open Child', isPrimary: true, cssClass: 'e-flat' },
click: () => childRef.current?.show(),
},
{
buttonModel: { content: 'Close', cssClass: 'e-flat' },
click: () => parentRef.current?.hide(),
},
];
const childButtons = [
{
buttonModel: { content: 'OK', isPrimary: true, cssClass: 'e-flat' },
click: () => childRef.current?.hide(),
},
{
buttonModel: { content: 'Cancel', cssClass: 'e-flat' },
click: () => childRef.current?.hide(),
},
];
return (
<div id="dialog-target" style={{ position: 'relative', minHeight: '500px' }}>
<button onClick={() => parentRef.current?.show()} className="e-btn">
Open Parent Dialog
</button>
{/* Parent Dialog */}
<DialogComponent
ref={parentRef}
header="Parent Dialog"
buttons={parentButtons}
isModal={true}
target="#dialog-target"
showCloseIcon={true}
zIndex={2000}
>
<p>This is the parent dialog.</p>
<p>Click "Open Child" to show a child dialog on top.</p>
</DialogComponent>
{/* Child Dialog - appears on top with higher z-index */}
<DialogComponent
ref={childRef}
header="Child Dialog"
buttons={childButtons}
isModal={true}
target="#dialog-target"
showCloseIcon={true}
zIndex={2001} {/* Higher than parent */}
>
<p>This child dialog appears on top of the parent.</p>
<p>Closing this doesn't close the parent.</p>
</DialogComponent>
</div>
);
}Multi-Level Nesting
// Parent → Child → Grandchild
const grandchildButtons = [
{
buttonModel: { content: 'Close', isPrimary: true, cssClass: 'e-flat' },
click: () => grandchildRef.current?.hide(),
},
];
<DialogComponent
ref={grandchildRef}
header="Grandchild Dialog"
buttons={grandchildButtons}
zIndex={2002} {/* Even higher */}
>
Third level dialog
</DialogComponent>Dialog with Forms
Form Submission
export function FormDialog() {
const dialogRef = useRef(null);
const [formData, setFormData] = React.useState({
name: '',
email: '',
message: '',
});
const handleInputChange = (field, value) => {
setFormData({ ...formData, [field]: value });
};
const handleSubmit = async () => {
console.log('Submitting:', formData);
try {
const response = await fetch('/api/submit', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(formData),
});
if (response.ok) {
alert('Submitted successfully');
dialogRef.current?.hide();
}
} catch (error) {
alert('Error submitting form');
}
};
const buttons = [
{
buttonModel: { content: 'Submit', isPrimary: true, cssClass: 'e-flat' },
click: handleSubmit,
},
{
buttonModel: { content: 'Cancel', cssClass: 'e-flat' },
click: () => dialogRef.current?.hide(),
},
];
return (
<div id="dialog-target" style={{ position: 'relative' }}>
<button onClick={() => dialogRef.current?.show()} className="e-btn">
Open Form
</button>
<DialogComponent
ref={dialogRef}
header="User Information"
buttons={buttons}
target="#dialog-target"
width="400px"
>
<form style={{ padding: '20px' }}>
<div style={{ marginBottom: '15px' }}>
<label style={{ display: 'block', marginBottom: '5px' }}>Name:</label>
<input
type="text"
className="e-input"
value={formData.name}
onChange={(e) => handleInputChange('name', e.target.value)}
placeholder="Enter your name"
style={{ width: '100%', padding: '8px', boxSizing: 'border-box' }}
/>
</div>
<div style={{ marginBottom: '15px' }}>
<label style={{ display: 'block', marginBottom: '5px' }}>Email:</label>
<input
type="email"
className="e-input"
value={formData.email}
onChange={(e) => handleInputChange('email', e.target.value)}
placeholder="Enter your email"
style={{ width: '100%', padding: '8px', boxSizing: 'border-box' }}
/>
</div>
<div style={{ marginBottom: '15px' }}>
<label style={{ display: 'block', marginBottom: '5px' }}>Message:</label>
<textarea
className="e-input"
value={formData.message}
onChange={(e) => handleInputChange('message', e.target.value)}
placeholder="Enter your message"
rows="4"
style={{ width: '100%', padding: '8px', boxSizing: 'border-box' }}
/>
</div>
</form>
</DialogComponent>
</div>
);
}Form Validation
export function ValidatedFormDialog() {
const dialogRef = useRef(null);
const [formData, setFormData] = React.useState({ email: '' });
const [errors, setErrors] = React.useState({});
const validateForm = () => {
const newErrors = {};
if (!formData.email) {
newErrors.email = 'Email is required';
} else if (!/\S+@\S+\.\S+/.test(formData.email)) {
newErrors.email = 'Email is invalid';
}
return newErrors;
};
const handleSubmit = () => {
const newErrors = validateForm();
if (Object.keys(newErrors).length === 0) {
console.log('Valid! Submitting:', formData);
dialogRef.current?.hide();
} else {
setErrors(newErrors);
}
};
const buttons = [
{
buttonModel: { content: 'Submit', isPrimary: true, cssClass: 'e-flat' },
click: handleSubmit,
},
];
return (
<div id="dialog-target" style={{ position: 'relative' }}>
<button onClick={() => dialogRef.current?.show()}>Open Form</button>
<DialogComponent
ref={dialogRef}
header="Email Form"
buttons={buttons}
target="#dialog-target"
width="400px"
>
<div style={{ padding: '20px' }}>
<label>Email:</label>
<input
type="email"
className="e-input"
value={formData.email}
onChange={(e) => setFormData({ email: e.target.value })}
style={{
width: '100%',
padding: '8px',
boxSizing: 'border-box',
borderColor: errors.email ? 'red' : '#ccc',
}}
/>
{errors.email && <span style={{ color: 'red' }}>{errors.email}</span>}
</div>
</DialogComponent>
</div>
);
}AJAX Content Loading
Load Content Dynamically
export function AjaxDialog() {
const dialogRef = useRef(null);
const [content, setContent] = React.useState('Loading...');
const loadContent = async () => {
dialogRef.current?.show();
try {
const response = await fetch('/api/dialog-content');
const data = await response.json();
setContent(data.content);
} catch (error) {
setContent('Error loading content');
}
};
return (
<div id="dialog-target" style={{ position: 'relative' }}>
<button onClick={loadContent} className="e-btn">
Load Content
</button>
<DialogComponent
ref={dialogRef}
header="Dynamic Content"
target="#dialog-target"
showCloseIcon={true}
>
{content}
</DialogComponent>
</div>
);
}Load on Dialog Open
<DialogComponent
ref={dialogRef}
header="Content"
open={async () => {
try {
const response = await fetch('/api/data');
const data = await response.json();
setContent(data.message);
} catch (error) {
setContent('Error loading');
}
}}
>
{content}
</DialogComponent>RTL Support
Enable RTL Direction
<div dir="rtl">
<DialogComponent
header="حوار"
isModal={true}
>
هذا محتوى باللغة العربية
</DialogComponent>
</div>RTL with CSS
<DialogComponent
className="rtl-dialog"
header="Dialog"
>
Content
</DialogComponent>.rtl-dialog {
direction: rtl;
text-align: right;
}
.rtl-dialog .e-dlg-header {
flex-direction: row-reverse;
}Prevent Closing on Backdrop Click
export function PreventCloseDialog() {
const dialogRef = useRef(null);
const [isSaved, setIsSaved] = React.useState(false);
const handleBeforeClose = (e) => {
if (!isSaved) {
e.cancel = true;
alert('Please save your changes first');
}
};
const handleSave = () => {
console.log('Saved');
setIsSaved(true);
};
const buttons = [
{
buttonModel: { content: 'Save', isPrimary: true, cssClass: 'e-flat' },
click: () => {
handleSave();
dialogRef.current?.hide();
},
},
{
buttonModel: { content: 'Discard', cssClass: 'e-flat' },
click: () => {
setIsSaved(true); // Skip validation
dialogRef.current?.hide();
},
},
];
return (
<div id="dialog-target" style={{ position: 'relative' }}>
<button onClick={() => dialogRef.current?.show()}>Open</button>
<DialogComponent
ref={dialogRef}
header="Edit"
buttons={buttons}
beforeClose={handleBeforeClose}
showCloseIcon={true}
isModal={true}
target="#dialog-target"
>
<input placeholder="Make changes" />
</DialogComponent>
</div>
);
}Full-Screen Dialogs
<DialogComponent
width="100%"
height="100vh"
position={{ X: 0, Y: 0 }}
enableResize={false}
allowDragging={false}
header="Full Screen Dialog"
>
Takes up entire viewport
</DialogComponent>Full-Screen with Content
export function FullScreenDialog() {
const dialogRef = useRef(null);
return (
<div id="dialog-target">
<button onClick={() => dialogRef.current?.show()}>Full Screen</button>
<DialogComponent
ref={dialogRef}
width="100%"
height="100%"
position={{ X: 0, Y: 0 }}
header="Full Screen Editor"
enableResize={false}
allowDragging={false}
target="#dialog-target"
buttons={[
{
buttonModel: { content: 'Exit', isPrimary: true, cssClass: 'e-flat' },
click: () => dialogRef.current?.hide(),
},
]}
>
<div style={{ padding: '20px', height: 'calc(100% - 100px)', overflow: 'auto' }}>
<textarea
style={{ width: '100%', height: '100%', fontSize: '16px' }}
placeholder="Type here..."
/>
</div>
</DialogComponent>
</div>
);
}Utility Functions
Create Alert Dialog
function createAlert(title, message) {
const alertRef = React.createRef();
return (
<DialogComponent
ref={alertRef}
header={title}
isModal={true}
buttons={[
{
buttonModel: { content: 'OK', isPrimary: true, cssClass: 'e-flat' },
click: () => alertRef.current?.hide(),
},
]}
>
{message}
</DialogComponent>
);
}
// Usage
const alert = createAlert('Warning', 'This action cannot be undone');Create Confirm Dialog
function createConfirm(title, message, onConfirm, onCancel) {
const confirmRef = React.createRef();
return (
<DialogComponent
ref={confirmRef}
header={title}
isModal={true}
buttons={[
{
buttonModel: { content: 'OK', isPrimary: true, cssClass: 'e-flat' },
click: () => {
onConfirm?.();
confirmRef.current?.hide();
},
},
{
buttonModel: { content: 'Cancel', cssClass: 'e-flat' },
click: () => {
onCancel?.();
confirmRef.current?.hide();
},
},
]}
>
{message}
</DialogComponent>
);
}Dialog Registry
export const DialogRegistry = {
dialogs: {},
register(name, dialogRef) {
this.dialogs[name] = dialogRef;
},
show(name) {
this.dialogs[name]?.show();
},
hide(name) {
this.dialogs[name]?.hide();
},
hideAll() {
Object.values(this.dialogs).forEach((ref) => ref?.hide());
},
};
// Usage
DialogRegistry.register('confirm', confirmRef);
DialogRegistry.show('confirm');
DialogRegistry.hideAll();Common Gotchas
Issue 1: Dialog Not Showing
// ❌ WRONG - No target container
<DialogComponent header="Dialog">Content</DialogComponent>
// ✅ CORRECT - Specify target
<div id="dialog-target" style={{ position: 'relative' }}>
<DialogComponent target="#dialog-target">Content</DialogComponent>
</div>Issue 2: CSS Not Loading
// ❌ WRONG - Missing theme CSS
import { DialogComponent } from '@syncfusion/ej2-react-popups';
// ✅ CORRECT - Import CSS
import '@syncfusion/ej2-react-popups/styles/tailwind3.css';
import { DialogComponent } from '@syncfusion/ej2-react-popups';Issue 3: Multiple Opens Not Working
// ❌ WRONG - Re-opening without closing
dialogRef.current?.show();
setTimeout(() => dialogRef.current?.show(), 500);
// ✅ CORRECT - Close before reopening
dialogRef.current?.hide();
setTimeout(() => dialogRef.current?.show(), 500);Issue 4: Z-Index Stacking
// ✅ CORRECT - Use different z-indices for nested dialogs
<DialogComponent zIndex={2000}>Parent</DialogComponent>
<DialogComponent zIndex={2001}>Child</DialogComponent>
<DialogComponent zIndex={2002}>Grandchild</DialogComponent>Issue 5: Dialog Height Not Set Correctly (Height Calculation)
The dialog's max-height is calculated based on the height of its target element. If the target has no explicit height (or defaults to document.body which has zero/auto height), the dialog height will not render correctly.
Root Cause: When target is not configured, document.body is used. If the dialog's height is larger than the body height, the height will not be applied.
// ❌ WRONG - body has no explicit height; dialog max-height calculation fails
<DialogComponent height="600px" isModal={true}>
Content
</DialogComponent>
// ✅ CORRECT - Add min-height to a custom target container
<div id="dialog-target" style={{ position: 'relative', minHeight: '700px' }}>
<DialogComponent
target="#dialog-target"
height="600px"
isModal={true}
>
Content
</DialogComponent>
</div>
// ✅ CORRECT - When using document.body as target, set CSS for both html and body/* Required when using document.body as the dialog target */
html, body {
height: 100%;
margin: 0;
}Key Rules:
- Always give the target element an explicit
min-heightorheight - When rendering against
document.body, ensurehtmlandbodyboth haveheight: 100% - Using percentage heights on the dialog (e.g.,
height="100%") requires the target container to have a defined height
Performance Tips
Lazy Load Content
const [isLoaded, setIsLoaded] = React.useState(false);
const handleOpen = () => {
if (!isLoaded) {
// Load heavy content only when needed
loadHeavyContent().then(() => setIsLoaded(true));
}
dialogRef.current?.show();
};
<DialogComponent open={handleOpen}>
{isLoaded && <HeavyComponent />}
</DialogComponent>Memoize Dialog Content
const DialogContent = React.memo(() => (
<div>Heavy computation content</div>
));
<DialogComponent>
<DialogContent />
</DialogComponent>Avoid Recreating Dialogs
// ❌ WRONG - Recreates dialog on every render
const MyComponent = () => {
return <DialogComponent header="Dialog">Content</DialogComponent>;
};
// ✅ CORRECT - Dialog is stable
const Dialog = () => (
<DialogComponent header="Dialog">Content</DialogComponent>
);
const MyComponent = () => <Dialog />;Migration from EJ1
EJ1 vs EJ2 Properties
| EJ1 | EJ2 | Notes |
|---|---|---|
isModal | isModal | Same |
title | header | Renamed |
content | children or content | Use children in React |
allowKeyboardInteraction | closeOnEscape | Controls Escape key behavior |
showCloseButton | showCloseIcon | Renamed |
buttons | buttons | Same structure, different API |
position | position | Same |
draggable | allowDragging | Renamed |
resizable | enableResize | Renamed; use resizeHandles for resize options |
Migration Example
// EJ1 Style
// $('#dialog').ejDialog({
// isModal: true,
// title: 'Dialog',
// content: 'Hello',
// buttons: [{ text: 'OK', click: function() { } }]
// });
// EJ2 Style (React)
import { DialogComponent } from '@syncfusion/ej2-react-popups';
<DialogComponent
ref={dialogRef}
isModal={true}
header="Dialog"
buttons={[{
buttonModel: { content: 'OK' },
click: () => {}
}]}
>
Hello
</DialogComponent>Next: Choose another reference topic based on your needs.
Animation Effects
Table of Contents
- Animation Settings
- Available Effects
- Effect Examples
- Duration and Delay
- Enable/Disable Animation
- Performance Considerations
Animation Settings
Control dialog open/close animations with the animationSettings property:
import React, { useRef } from 'react';
import { DialogComponent } from '@syncfusion/ej2-react-popups';
import './App.css';
export default function App() {
const dialogRef = useRef(null);
const animationSettings = {
effect: 'Zoom', // Animation type
duration: 400, // Milliseconds
delay: 0 // Initial delay in milliseconds
};
return (
<div id="dialog-target" style={{ position: 'relative' }}>
<button onClick={() => dialogRef.current?.show()}>Open</button>
<DialogComponent
ref={dialogRef}
header="Animated Dialog"
animationSettings={animationSettings}
target="#dialog-target"
>
Smooth animation on open/close
</DialogComponent>
</div>
);
}Available Effects
The Dialog supports 15+ animation effects:
| Effect | Open | Close | Description |
|---|---|---|---|
'Fade' | FadeIn | FadeOut | Opacity transition |
'FadeZoom' | FadeIn + ZoomIn | FadeOut + ZoomOut | Fade + scale combined |
'FlipLeftDown' | Flip left-down | Reverse | 3D flip effect |
'FlipLeftUp' | Flip left-up | Reverse | 3D flip effect |
'FlipRightDown' | Flip right-down | Reverse | 3D flip effect |
'FlipRightUp' | Flip right-up | Reverse | 3D flip effect |
'FlipXDown' | Flip X-down | Reverse | Horizontal flip |
'FlipXUp' | Flip X-up | Reverse | Horizontal flip |
'FlipYLeft' | Flip Y-left | Reverse | Vertical flip |
'FlipYRight' | Flip Y-right | Reverse | Vertical flip |
'SlideBottom' | Slide from bottom | Slide to bottom | Top-to-bottom |
'SlideLeft' | Slide from left | Slide to left | Left-to-right |
'SlideRight' | Slide from right | Slide to right | Right-to-left |
'SlideTop' | Slide from top | Slide to top | Bottom-to-top |
'Zoom' | ZoomIn | ZoomOut | Scale animation |
'None' | No animation | No animation | Instant appearance |
Effect Examples
Example 1: Fade Effect (Gentle)
<DialogComponent
animationSettings={{
effect: 'Fade',
duration: 300,
delay: 0
}}
>
Fades in smoothly
</DialogComponent>Example 2: Zoom Effect (Attention-grabbing)
<DialogComponent
animationSettings={{
effect: 'Zoom',
duration: 500,
delay: 0
}}
>
Zooms in from center
</DialogComponent>Example 3: Slide Top (Professional)
<DialogComponent
animationSettings={{
effect: 'SlideTop',
duration: 400,
delay: 0
}}
>
Slides down from top
</DialogComponent>Example 4: Flip (Dramatic)
<DialogComponent
animationSettings={{
effect: 'FlipXUp',
duration: 600,
delay: 0
}}
>
Flips up dramatically
</DialogComponent>Example 5: Slide Bottom (Emphasis)
<DialogComponent
animationSettings={{
effect: 'SlideBottom',
duration: 350,
delay: 0
}}
>
Slides up from bottom
</DialogComponent>Comparing Effects
export function AnimationGallery() {
const dialogRef = useRef(null);
const [effect, setEffect] = React.useState('Fade');
const effects = [
'Fade', 'FadeZoom', 'Zoom',
'SlideTop', 'SlideBottom', 'SlideLeft', 'SlideRight',
'FlipXUp', 'FlipYLeft', 'None'
];
const showWithEffect = (selectedEffect) => {
setEffect(selectedEffect);
// Close and reopen to trigger animation
dialogRef.current?.hide();
setTimeout(() => dialogRef.current?.show(), 100);
};
return (
<div id="dialog-target" style={{ position: 'relative', height: '500px' }}>
<div style={{ padding: '20px' }}>
<h3>Choose Animation Effect:</h3>
<div style={{ display: 'grid', gridTemplateColumns: 'repeat(3, 1fr)', gap: '10px' }}>
{effects.map((eff) => (
<button
key={eff}
onClick={() => showWithEffect(eff)}
style={{
padding: '10px',
background: eff === effect ? '#667eea' : '#e5e7eb',
color: eff === effect ? 'white' : 'black',
border: 'none',
borderRadius: '4px',
cursor: 'pointer',
}}
>
{eff}
</button>
))}
</div>
</div>
<DialogComponent
ref={dialogRef}
header="Animation Demo"
animationSettings={{
effect: effect,
duration: 400,
delay: 0
}}
target="#dialog-target"
showCloseIcon={true}
>
Preview: <strong>{effect}</strong> animation
</DialogComponent>
</div>
);
}Duration and Delay
Duration (Animation Speed)
Controls how long the animation takes in milliseconds:
// Fast (200ms)
animationSettings={{ effect: 'Fade', duration: 200 }}
// Normal (400ms)
animationSettings={{ effect: 'Fade', duration: 400 }}
// Slow (800ms)
animationSettings={{ effect: 'Fade', duration: 800 }}
// Very Slow (1200ms)
animationSettings={{ effect: 'Fade', duration: 1200 }}Delay (Wait Before Animation)
Initial delay before animation starts:
// No delay
animationSettings={{ effect: 'Zoom', duration: 400, delay: 0 }}
// 100ms delay
animationSettings={{ effect: 'Zoom', duration: 400, delay: 100 }}
// 500ms delay
animationSettings={{ effect: 'Zoom', duration: 400, delay: 500 }}Common Combinations
// Snappy (quick with no delay)
{ effect: 'Fade', duration: 200, delay: 0 }
// Smooth (moderate speed, no delay)
{ effect: 'SlideTop', duration: 400, delay: 0 }
// Delayed announcement (with delay before animation)
{ effect: 'Zoom', duration: 500, delay: 200 }
// Slow emphasis (longer animation)
{ effect: 'FadeZoom', duration: 800, delay: 0 }Example: Adjustable Speed
export function AdjustableAnimation() {
const dialogRef = useRef(null);
const [duration, setDuration] = React.useState(400);
return (
<div id="dialog-target" style={{ position: 'relative' }}>
<div style={{ padding: '20px' }}>
<label>
Animation Duration (ms):
<input
type="range"
min="100"
max="1000"
step="100"
value={duration}
onChange={(e) => setDuration(Number(e.target.value))}
/>
{duration}ms
</label>
</div>
<button onClick={() => dialogRef.current?.show()}>Open</button>
<DialogComponent
ref={dialogRef}
header="Adjustable Speed"
animationSettings={{
effect: 'Zoom',
duration: duration,
delay: 0
}}
target="#dialog-target"
>
Adjust the slider to change animation speed
</DialogComponent>
</div>
);
}Enable/Disable Animation
Disable Animation
// Option 1: Use 'None' effect
<DialogComponent
animationSettings={{ effect: 'None' }}
>
No animation
</DialogComponent>
// Option 2: Set duration to 0
<DialogComponent
animationSettings={{ effect: 'Fade', duration: 0, delay: 0 }}
>
Instant appearance
</DialogComponent>
// Option 3: Omit animationSettings
<DialogComponent>
Default behavior (usually no animation)
</DialogComponent>Toggle Animation
export function ToggleAnimation() {
const dialogRef = useRef(null);
const [animated, setAnimated] = React.useState(true);
const animationSettings = animated
? { effect: 'Zoom', duration: 400, delay: 0 }
: { effect: 'None' };
return (
<div id="dialog-target" style={{ position: 'relative' }}>
<label>
<input
type="checkbox"
checked={animated}
onChange={(e) => setAnimated(e.target.checked)}
/>
Enable Animation
</label>
<button onClick={() => dialogRef.current?.show()}>Open</button>
<DialogComponent
ref={dialogRef}
header="Toggle Animation"
animationSettings={animationSettings}
target="#dialog-target"
>
Animation is {animated ? 'ON' : 'OFF'}
</DialogComponent>
</div>
);
}Performance Considerations
Animation Impact on Performance
- Simple effects (Fade, Zoom): Minimal performance cost
- Complex effects (Flip, FadeZoom): Higher GPU usage
- Long duration: Longer animation = more frame rendering
- Multiple dialogs: Each animated dialog consumes resources
Best Practices
// ✅ GOOD: Fast, simple animations for better performance
animationSettings={{
effect: 'Fade',
duration: 300,
delay: 0
}}
// ❌ AVOID: Complex, long animations on constrained devices
animationSettings={{
effect: 'FlipRightDown',
duration: 2000,
delay: 500
}}Disable Animation on Low-End Devices
// Detect device capability
const isLowEndDevice = navigator.deviceMemory < 4;
const animationSettings = isLowEndDevice
? { effect: 'None' }
: { effect: 'Zoom', duration: 400, delay: 0 };
<DialogComponent animationSettings={animationSettings}>
Content
</DialogComponent>Responsive Animation
const isMobile = window.innerWidth < 768;
const animationSettings = isMobile
? { effect: 'Fade', duration: 200, delay: 0 } // Faster on mobile
: { effect: 'Zoom', duration: 400, delay: 0 }; // Slower on desktop
<DialogComponent animationSettings={animationSettings}>
Content
</DialogComponent>Animation During Heavy Processing
export function AnimationWithProcessing() {
const dialogRef = useRef(null);
const [isProcessing, setIsProcessing] = React.useState(false);
const handleOpen = () => {
// Disable animation while processing
const hasAnimation = !isProcessing;
dialogRef.current?.show();
};
const animationSettings = isProcessing
? { effect: 'None' }
: { effect: 'Zoom', duration: 400, delay: 0 };
return (
<div id="dialog-target" style={{ position: 'relative' }}>
<button onClick={handleOpen}>Open</button>
<DialogComponent
ref={dialogRef}
header="Processing"
animationSettings={animationSettings}
target="#dialog-target"
>
{isProcessing ? '⏳ Processing...' : '✅ Done'}
</DialogComponent>
</div>
);
}Animation Queuing
For multiple dialogs, stagger animations:
<DialogComponent
ref={dialog1Ref}
animationSettings={{ effect: 'Zoom', duration: 400, delay: 0 }}
>
First dialog - immediate
</DialogComponent>
<DialogComponent
ref={dialog2Ref}
animationSettings={{ effect: 'Zoom', duration: 400, delay: 200 }}
>
Second dialog - 200ms delay
</DialogComponent>
<DialogComponent
ref={dialog3Ref}
animationSettings={{ effect: 'Zoom', duration: 400, delay: 400 }}
>
Third dialog - 400ms delay
</DialogComponent>Use Case Recommendations
| Use Case | Effect | Duration | Reason |
|---|---|---|---|
| Alert/Warning | Zoom | 300-400ms | Attention-grabbing |
| Confirmation | Fade | 250-300ms | Quick and professional |
| Information | SlideTop | 350-450ms | Gentle, informative |
| Complex Form | FadeZoom | 400-500ms | Signals importance |
| Notification | SlideTop | 200-300ms | Quick appearance |
| Help/Tutorial | Fade | 300-400ms | Non-intrusive |
| Loading Dialog | None | — | No animation needed |
| Unexpected Error | Zoom | 400-500ms | Emphasizes issue |
Next: Choose another reference topic based on your needs.
Dialog API Reference
Complete API documentation for Syncfusion React DialogComponent from official EJ2 documentation.
Table of Contents
- Component
- Properties (DialogModel)
- Methods
- Events
- Button Properties (ButtonPropsModel)
- Animation Settings (AnimationSettingsModel)
- Types and Enumerations
- Quick Reference
---
Component
DialogComponent
The main React component for displaying dialogs and modal windows.
Package: @syncfusion/ej2-react-popups
Import:
import { DialogComponent } from '@syncfusion/ej2-react-popups';Basic Usage:
<DialogComponent
ref={dialogRef}
header="Title"
width="400px"
visible={false}
isModal={true}
>
Dialog content goes here
</DialogComponent>---
Properties (DialogModel)
Core Properties
header
- Type:
string | HTMLElement | Function - Default:
null - Description: Specifies the value that can be displayed in the dialog's title area
- Example:
<DialogComponent header="Welcome to Dialog" />
// With JSX
<DialogComponent header={<div>Custom <strong>Header</strong></div>} />content
- Type:
string | HTMLElement | Function - Default:
null - Description: Specifies the value displayed in dialog's content area
- Example:
<DialogComponent content="This is content" />
// With JSX
<DialogComponent content={<div><p>Rich content</p></div>} />width
- Type:
string | number - Default:
'330px' - Description: Specifies the width of the dialog component
- Example:
<DialogComponent width="400px" />
<DialogComponent width={500} />
<DialogComponent width="80%" />height
- Type:
string | number - Default:
'auto' - Description: Specifies the height of the dialog component
- Important: The dialog's
max-heightis calculated based on the height of its target element. If the dialog's height is larger than the target (body) height, the dialog height will not be set correctly. Always ensure the target container has proper dimensions. - Example:
<DialogComponent height="300px" />
<DialogComponent height={400} />
<DialogComponent height="100%" />minHeight
- Type:
string | number - Default:
null - Description: Specifies the minimum height of the dialog during resize
- Example:
<DialogComponent minHeight="200px" enableResize={true} />Visibility and Modal Properties
visible
- Type:
boolean - Default:
false - Description: Specifies whether the dialog component is visible
- Example:
const [isVisible, setIsVisible] = useState(false);
<DialogComponent visible={isVisible} />isModal
- Type:
boolean - Default:
false - Description: Specifies if the dialog can be displayed as modal (blocks parent) or modeless
- Example:
<DialogComponent isModal={true} /> // Blocks interaction
<DialogComponent isModal={false} /> // Allows interactioncloseOnEscape
- Type:
boolean - Default:
true - Description: Specifies whether dialog can be closed with Escape key
- Example:
<DialogComponent closeOnEscape={true} />
<DialogComponent closeOnEscape={false} />Positioning and Layout Properties
position
- Type:
PositionDataModel - Default:
{ X: 'center', Y: 'center' } - Description: Specifies where the dialog can be positioned
- PositionDataModel:
{
X: 'left' | 'center' | 'right' | number, // X position
Y: 'top' | 'center' | 'bottom' | number // Y position
}- Example:
// Preset positions
<DialogComponent position={{ X: 'center', Y: 'center' }} />
<DialogComponent position={{ X: 'left', Y: 'top' }} />
<DialogComponent position={{ X: 'right', Y: 'bottom' }} />
// Custom pixels
<DialogComponent position={{ X: 100, Y: 50 }} />
// Mixed
<DialogComponent position={{ X: 'center', Y: 100 }} />target
- Type:
HTMLElement | string - Default:
document.body - Description: Specifies the target element in which the dialog displays (required for modal)
- Important: The dialog's
max-heightis calculated based on this target element's height. Iftargetis not configured,document.bodyis used. To ensure the dialog displays at its proper height, the target element must have an explicitmin-heightorheight. Whendocument.bodyis the target, set CSS for bothhtmlandbodyso the dialog can size correctly:
html, body {
height: 100%;
margin: 0;
}- Example:
<div id="dialog-container" style={{ position: 'relative', minHeight: '500px' }}>
<DialogComponent
target="#dialog-container"
isModal={true}
/>
</div>zIndex
- Type:
number - Default:
auto - Description: Specifies z-order for rendering (determines front/back display)
- Example:
<DialogComponent zIndex={2000} />
<DialogComponent zIndex={2001} /> // Appears in frontInteraction Properties
allowDragging
- Type:
boolean - Default:
false - Description: Specifies whether dialog component can be dragged
- Example:
<DialogComponent
allowDragging={true}
position={{ X: 100, Y: 100 }}
/>enableResize
- Type:
boolean - Default:
false - Description: Specifies whether dialog component can be resized
- Example:
<DialogComponent
enableResize={true}
resizeHandles={['All']}
/>resizeHandles
- Type:
ResizeDirections[] - Default:
['All'] - Description: Specifies which resize handles direction in dialog
- ResizeDirections:
'All' | 'North' | 'South' | 'East' | 'West' | 'NorthEast' | 'NorthWest' | 'SouthEast' | 'SouthWest' - Example:
<DialogComponent
enableResize={true}
resizeHandles={['All']}
/>
<DialogComponent
enableResize={true}
resizeHandles={['East', 'West', 'South']}
/>Button and Template Properties
buttons
- Type:
ButtonPropsModel[] - Default:
null - Description: Configures action buttons with button properties
- Example:
const buttons = [
{
buttonModel: {
content: 'OK',
isPrimary: true,
cssClass: 'e-flat'
},
click: handleOK
},
{
buttonModel: {
content: 'Cancel',
cssClass: 'e-flat'
},
click: handleCancel
}
];
<DialogComponent buttons={buttons} />footerTemplate
- Type:
HTMLElement | string | Function - Default:
null - Description: Specifies custom footer template (replaces buttons)
- Example:
<DialogComponent
footerTemplate={
<div style={{ padding: '12px', textAlign: 'right' }}>
<button>Save</button>
<button>Cancel</button>
</div>
}
/>showCloseIcon
- Type:
boolean - Default:
false - Description: Specifies whether close icon is shown in header
- Example:
<DialogComponent showCloseIcon={true} />Animation Properties
animationSettings
- Type:
AnimationSettingsModel - Default:
null - Description: Specifies animation settings for dialog open/close
- Example:
<DialogComponent
animationSettings={{
effect: 'Zoom',
duration: 400,
delay: 0
}}
/>Customization Properties
cssClass
- Type:
string - Default:
null - Description: Specifies CSS classes to append to root element
- Example:
<DialogComponent cssClass="custom-dialog dark-theme" />enableHtmlSanitizer
- Type:
boolean - Default:
true - Description: Defines whether to sanitize HTML content (security)
- Example:
<DialogComponent enableHtmlSanitizer={true} />enableRtl
- Type:
boolean - Default:
false - Description: Enable/disable rendering in right-to-left direction
- Example:
<DialogComponent enableRtl={true} />locale
- Type:
string - Default:
'en-US' - Description: Overrides global culture and localization for this component
- Example:
<DialogComponent locale="de" />
<DialogComponent locale="es" />
<DialogComponent locale="fr" />
<DialogComponent locale="ja" />
<DialogComponent locale="zh" />enablePersistence
- Type:
boolean - Default:
false - Description: Enables persistence of dialog dimensions and position between page reloads
- Example:
<DialogComponent enablePersistence={true} />---
Methods
Public Methods
show()
- Description: Display the dialog
- Syntax:
dialogRef.current?.show() - Return Type:
void - Example:
const dialogRef = useRef(null);
const handleOpen = () => {
dialogRef.current?.show();
};hide()
- Description: Hide the dialog
- Syntax:
dialogRef.current?.hide() - Return Type:
void - Example:
const handleClose = () => {
dialogRef.current?.hide();
};refresh()
- Description: Refresh the dialog (recalculate position)
- Syntax:
dialogRef.current?.refresh() - Return Type:
void - Example:
const handleRefresh = () => {
dialogRef.current?.refresh();
};destroy()
- Description: Destroy the dialog component and clean up resources
- Syntax:
dialogRef.current?.destroy() - Return Type:
void - Example:
useEffect(() => {
return () => {
dialogRef.current?.destroy();
};
}, []);---
Events
Dialog Events
All events receive the event arguments as callback parameter.
beforeOpen
- Type:
EmitType<BeforeOpenEventArgs> - Description: Event triggers when dialog is being opened (can be cancelled)
- Can Cancel: Yes
- Example:
const handleBeforeOpen = (args) => {
console.log('Dialog opening...');
// args.cancel = true; // Prevent opening
};
<DialogComponent beforeOpen={handleBeforeOpen} />open
- Type:
EmitType<OpenEventArgs> - Description: Event triggers after dialog has opened
- Example:
const handleOpen = (args) => {
console.log('Dialog opened');
};
<DialogComponent open={handleOpen} />beforeClose
- Type:
EmitType<BeforeCloseEventArgs> - Description: Event triggers before dialog closes (can be cancelled)
- Can Cancel: Yes
- Example:
const handleBeforeClose = (args) => {
if (hasUnsavedChanges) {
args.cancel = true; // Prevent closing
}
};
<DialogComponent beforeClose={handleBeforeClose} />close
- Type:
EmitType<CloseEventArgs> - Description: Event triggers after dialog has closed
- Example:
const handleClose = (args) => {
console.log('Dialog closed');
};
<DialogComponent close={handleClose} />Drag Events
dragStart
- Type:
EmitType<DragStartEventArgs> - Description: Event triggers when user begins dragging dialog
- Example:
const handleDragStart = (args) => {
console.log('Drag started at:', args.clientX, args.clientY);
};
<DialogComponent
allowDragging={true}
dragStart={handleDragStart}
/>drag
- Type:
EmitType<DragEventArgs> - Description: Event triggers while user is dragging dialog
- Example:
const handleDrag = (args) => {
console.log('Dragging:', args.clientX, args.clientY);
};
<DialogComponent
allowDragging={true}
drag={handleDrag}
/>dragStop
- Type:
EmitType<DragStopEventArgs> - Description: Event triggers when user stops dragging dialog
- Example:
const handleDragStop = (args) => {
console.log('Drag stopped');
};
<DialogComponent
allowDragging={true}
dragStop={handleDragStop}
/>Resize Events
resizeStart
- Type:
EmitType<Object> - Description: Event triggers when user begins resizing dialog
- Example:
const handleResizeStart = (args) => {
console.log('Resize started');
};
<DialogComponent
enableResize={true}
resizeStart={handleResizeStart}
/>resizing
- Type:
EmitType<Object> - Description: Event triggers while user is resizing dialog
- Example:
const handleResizing = (args) => {
console.log('Resizing...');
};
<DialogComponent
enableResize={true}
resizing={handleResizing}
/>resizeStop
- Type:
EmitType<Object> - Description: Event triggers when user stops resizing dialog
- Example:
const handleResizeStop = (args) => {
console.log('Resize stopped');
};
<DialogComponent
enableResize={true}
resizeStop={handleResizeStop}
/>Other Events
overlayClick
- Type:
EmitType<Object> - Description: Event triggers when overlay (backdrop) is clicked in modal dialogs
- Example:
const handleOverlayClick = (args) => {
console.log('Overlay clicked');
};
<DialogComponent
isModal={true}
overlayClick={handleOverlayClick}
/>created
- Type:
EmitType<Object> - Description: Event triggers when dialog is created
- Example:
const handleCreated = () => {
console.log('Dialog component created');
};
<DialogComponent created={handleCreated} />destroyed
- Type:
EmitType<Event> - Description: Event triggers when dialog is destroyed
- Example:
const handleDestroyed = () => {
console.log('Dialog destroyed');
};
<DialogComponent destroyed={handleDestroyed} />---
Button Properties (ButtonPropsModel)
ButtonPropsModel Structure
Each button in the buttons array follows this structure:
{
buttonModel: ButtonModel, // Button configuration
click: EmitType<Object>, // Click event handler
isFlat?: boolean, // Flat appearance (default: true)
type?: ButtonType // Button type
}ButtonModel Properties
content
- Type:
string - Description: Button text/label
- Example:
{ content: 'Save' }
isPrimary
- Type:
boolean - Default:
false - Description: Highlight button as primary action
- Example:
{ isPrimary: true }
cssClass
- Type:
string - Description: CSS classes for styling
- Common Classes:
e-flat- Flat stylee-outline- Outline stylee-danger- Red danger colore-success- Green success colore-warning- Yellow warning color- Example:
{ cssClass: 'e-flat e-danger' }
id
- Type:
string - Description: HTML id for button element
- Example:
{ id: 'save-btn' }
iconCss
- Type:
string - Description: Icon class (Font Awesome, Material Icons)
- Example:
{ iconCss: 'e-icons e-save' }
ButtonType Enumeration
'Button'- Standard button (default)'Submit'- Submit form'Reset'- Reset form
Complete Button Example
const buttons = [
{
buttonModel: {
content: 'Save',
cssClass: 'e-flat e-primary',
isPrimary: true,
iconCss: 'e-icons e-save',
id: 'save-btn'
},
click: handleSave,
isFlat: true,
type: 'Submit'
},
{
buttonModel: {
content: 'Cancel',
cssClass: 'e-flat',
id: 'cancel-btn'
},
click: handleCancel,
isFlat: true,
type: 'Button'
}
];---
Animation Settings (AnimationSettingsModel)
AnimationSettingsModel Properties
effect
- Type:
DialogEffect - Default:
'Fade' - Description: Animation effect for open/close
- Supported Effects:
1. 'Fade' - Opacity transition 2. 'FadeZoom' - Fade + zoom combined 3. 'FlipLeftDown' - 3D flip left-down 4. 'FlipLeftUp' - 3D flip left-up 5. 'FlipRightDown' - 3D flip right-down 6. 'FlipRightUp' - 3D flip right-up 7. 'FlipXDown' - Horizontal flip down 8. 'FlipXUp' - Horizontal flip up 9. 'FlipYLeft' - Vertical flip left 10. 'FlipYRight' - Vertical flip right 11. 'SlideBottom' - Slide from bottom 12. 'SlideLeft' - Slide from left 13. 'SlideRight' - Slide from right 14. 'SlideTop' - Slide from top 15. 'Zoom' - Scale animation 16. 'None' - No animation
duration
- Type:
number - Default:
400 - Description: Animation duration in milliseconds
- Example:
{ duration: 300 }- 300ms animation
delay
- Type:
number - Default:
0 - Description: Delay before animation starts in milliseconds
- Example:
{ delay: 100 }- 100ms delay before animation
AnimationSettingsModel Examples
// Fast zoom
<DialogComponent
animationSettings={{
effect: 'Zoom',
duration: 200,
delay: 0
}}
/>
// Slow slide with delay
<DialogComponent
animationSettings={{
effect: 'SlideBottom',
duration: 600,
delay: 100
}}
/>
// 3D flip
<DialogComponent
animationSettings={{
effect: 'FlipLeftDown',
duration: 500,
delay: 0
}}
/>
// No animation
<DialogComponent
animationSettings={{
effect: 'None'
}}
/>---
Types and Enumerations
DialogEffect
Animation effects available for dialog:
type DialogEffect =
'Fade' | 'FadeZoom' | 'FlipLeftDown' | 'FlipLeftUp' |
'FlipRightDown' | 'FlipRightUp' | 'FlipXDown' | 'FlipXUp' |
'FlipYLeft' | 'FlipYRight' | 'SlideBottom' | 'SlideLeft' |
'SlideRight' | 'SlideTop' | 'Zoom' | 'None';ResizeDirections
Resize handle directions:
type ResizeDirections =
'All' | 'North' | 'South' | 'East' | 'West' |
'NorthEast' | 'NorthWest' | 'SouthEast' | 'SouthWest';ButtonType
Button type enumeration:
type ButtonType = 'Button' | 'Submit' | 'Reset';PositionDataModel
Position configuration:
interface PositionDataModel {
X: 'left' | 'center' | 'right' | number;
Y: 'top' | 'center' | 'bottom' | number;
}---
Quick Reference
Common Property Combinations
Modal Confirmation Dialog:
<DialogComponent
header="Confirm"
isModal={true}
showCloseIcon={true}
buttons={[
{ buttonModel: { content: 'OK', isPrimary: true }, click: handleOK },
{ buttonModel: { content: 'Cancel' }, click: handleCancel }
]}
width="400px"
position={{ X: 'center', Y: 'center' }}
/>Draggable Tool Panel:
<DialogComponent
header="Tools"
isModal={false}
allowDragging={true}
enableResize={true}
position={{ X: 100, Y: 100 }}
width="300px"
showCloseIcon={true}
/>Animated Modal:
<DialogComponent
header="Welcome"
isModal={true}
animationSettings={{ effect: 'Zoom', duration: 400 }}
position={{ X: 'center', Y: 'center' }}
width="500px"
/>Localized Dialog:
<DialogComponent
header="Dialog"
locale="es"
enableRtl={true}
isModal={true}
/>Event Examples
<DialogComponent
ref={dialogRef}
header="Event Example"
beforeOpen={(args) => console.log('Before open')}
open={(args) => console.log('Opened')}
beforeClose={(args) => console.log('Before close')}
close={(args) => console.log('Closed')}
dragStart={(args) => console.log('Drag started')}
drag={(args) => console.log('Dragging')}
dragStop={(args) => console.log('Drag stopped')}
/>---
Buttons and Actions
Table of Contents
- Built-in Button Support
- Button Model Properties
- Click Event Handlers
- Icon Buttons
- Styling Buttons
- Primary and Secondary Buttons
- Common Patterns
- Edge Cases
Built-in Button Support
The Dialog supports built-in footer buttons via the buttons property:
import React, { useRef } from 'react';
import { DialogComponent } from '@syncfusion/ej2-react-popups';
import './App.css';
export default function App() {
const dialogRef = useRef(null);
const buttons = [
{
buttonModel: {
content: 'OK',
cssClass: 'e-flat',
isPrimary: true,
},
click: () => {
console.log('OK clicked');
dialogRef.current?.hide();
},
},
{
buttonModel: {
content: 'Cancel',
cssClass: 'e-flat',
},
click: () => dialogRef.current?.hide(),
},
];
return (
<div id="dialog-target" style={{ position: 'relative' }}>
<button onClick={() => dialogRef.current?.show()}>Open</button>
<DialogComponent
ref={dialogRef}
header="Confirmation"
buttons={buttons}
target="#dialog-target"
>
Are you sure?
</DialogComponent>
</div>
);
}Button Model Properties
Each button in the array has a buttonModel object:
| Property | Type | Description |
|---|---|---|
content | string | Button text/label |
cssClass | string | CSS classes (e.g., 'e-flat', 'e-outline') |
isPrimary | boolean | Highlight as primary action |
isDisabled | boolean | Disable button |
iconCss | string | Icon class (Font Awesome, Material Icons) |
id | string | Button HTML id |
Example with Full Properties
const buttons = [
{
buttonModel: {
content: 'Save',
cssClass: 'e-flat e-primary',
isPrimary: true,
iconCss: 'e-icons e-save',
id: 'save-btn',
},
click: handleSave,
},
{
buttonModel: {
content: 'Delete',
cssClass: 'e-flat e-danger',
iconCss: 'e-icons e-delete',
id: 'delete-btn',
},
click: handleDelete,
},
];Click Event Handlers
Each button has a click callback:
const buttons = [
{
buttonModel: { content: 'Submit', isPrimary: true, cssClass: 'e-flat' },
click: () => {
console.log('Submit clicked');
// Perform action
dialogRef.current?.hide();
},
},
];Access Button Data in Handler
const buttons = [
{
buttonModel: { content: 'Action 1', cssClass: 'e-flat' },
click: function() {
// 'this' refers to the button element
console.log(this.textContent); // "Action 1"
},
},
];Multiple Actions
const handleApply = () => {
console.log('Apply clicked');
saveData();
refreshUI();
dialogRef.current?.hide();
};
const buttons = [
{
buttonModel: { content: 'Apply', isPrimary: true, cssClass: 'e-flat' },
click: handleApply,
},
];Icon Buttons
With Syncfusion Icons
const buttons = [
{
buttonModel: {
content: 'Save',
cssClass: 'e-flat',
iconCss: 'e-icons e-save',
},
click: () => console.log('Save'),
},
{
buttonModel: {
content: 'Delete',
cssClass: 'e-flat',
iconCss: 'e-icons e-delete',
},
click: () => console.log('Delete'),
},
];Available Syncfusion Icons
e-save- Save icone-delete- Delete icone-edit- Edit icone-update- Update/refresh icone-print- Print icone-export- Export icone-close- Close icone-search- Search icone-settings- Settings icon
Font Awesome Icons
const buttons = [
{
buttonModel: {
content: 'Download',
cssClass: 'e-flat',
iconCss: 'fa fa-download',
},
click: () => console.log('Download'),
},
{
buttonModel: {
content: 'Share',
cssClass: 'e-flat',
iconCss: 'fa fa-share',
},
click: () => console.log('Share'),
},
];Material Icons
const buttons = [
{
buttonModel: {
content: 'Favorite',
cssClass: 'e-flat',
iconCss: 'material-icons',
content: '<span class="material-icons">favorite</span> Favorite',
},
click: () => console.log('Favorite'),
},
];Styling Buttons
CSS Classes
Built-in classes:
e-flat- Flat button stylee-outline- Outline stylee-primary- Primary theme color (combine with isPrimary)e-danger- Red danger stylee-success- Green success stylee-warning- Yellow warning stylee-info- Blue info stylee-small- Smaller buttone-large- Larger button
Styling Examples
const buttons = [
{
buttonModel: {
content: 'Primary',
cssClass: 'e-flat e-primary',
isPrimary: true,
},
click: () => {},
},
{
buttonModel: {
content: 'Danger',
cssClass: 'e-flat e-danger',
},
click: () => {},
},
{
buttonModel: {
content: 'Success',
cssClass: 'e-flat e-success',
},
click: () => {},
},
];Custom CSS
const buttons = [
{
buttonModel: {
content: 'Custom',
cssClass: 'my-custom-button',
},
click: () => {},
},
];.my-custom-button {
background: linear-gradient(to right, #667eea, #764ba2) !important;
color: white !important;
border: none !important;
font-weight: bold !important;
}
.my-custom-button:hover {
opacity: 0.8;
}Primary and Secondary Buttons
Marking Primary Action
const buttons = [
{
buttonModel: {
content: 'Save',
cssClass: 'e-flat',
isPrimary: true, // Highlighted as main action
},
click: handleSave,
},
{
buttonModel: {
content: 'Cancel',
cssClass: 'e-flat',
isPrimary: false, // Secondary action
},
click: handleCancel,
},
];Visual difference: Primary button has different background color.
Confirmation Pattern
const buttons = [
{
buttonModel: {
content: 'Delete',
cssClass: 'e-flat e-danger',
isPrimary: true, // Dangerous action as primary
},
click: handleDelete,
},
{
buttonModel: {
content: 'Cancel',
cssClass: 'e-flat',
},
click: handleCancel,
},
];Common Patterns
Pattern 1: OK/Cancel Dialog
export function ConfirmDialog() {
const dialogRef = useRef(null);
const buttons = [
{
buttonModel: { content: 'OK', isPrimary: true, cssClass: 'e-flat' },
click: () => {
console.log('Confirmed');
dialogRef.current?.hide();
},
},
{
buttonModel: { content: 'Cancel', cssClass: 'e-flat' },
click: () => dialogRef.current?.hide(),
},
];
return (
<div id="dialog-target" style={{ position: 'relative' }}>
<button onClick={() => dialogRef.current?.show()}>Confirm</button>
<DialogComponent
ref={dialogRef}
header="Confirm Action"
buttons={buttons}
target="#dialog-target"
>
Proceed with this action?
</DialogComponent>
</div>
);
}Pattern 2: Yes/No Dialog
const buttons = [
{
buttonModel: { content: 'Yes', isPrimary: true, cssClass: 'e-flat e-success' },
click: handleYes,
},
{
buttonModel: { content: 'No', cssClass: 'e-flat' },
click: handleNo,
},
];Pattern 3: Multiple Actions
const buttons = [
{
buttonModel: { content: 'Save', isPrimary: true, cssClass: 'e-flat' },
click: handleSave,
},
{
buttonModel: { content: 'Save As', cssClass: 'e-flat' },
click: handleSaveAs,
},
{
buttonModel: { content: 'Cancel', cssClass: 'e-flat' },
click: handleCancel,
},
];Pattern 4: Single Button (Alert)
const buttons = [
{
buttonModel: { content: 'OK', isPrimary: true, cssClass: 'e-flat' },
click: () => dialogRef.current?.hide(),
},
];Pattern 5: Form Actions
const buttons = [
{
buttonModel: { content: 'Submit', isPrimary: true, cssClass: 'e-flat' },
click: handleSubmit,
},
{
buttonModel: { content: 'Reset', cssClass: 'e-flat' },
click: handleReset,
},
{
buttonModel: { content: 'Cancel', cssClass: 'e-flat' },
click: handleCancel,
},
];Pattern 6: Delete Dialog (Danger Pattern)
export function DeleteDialog() {
const dialogRef = useRef(null);
const buttons = [
{
buttonModel: {
content: 'Delete',
cssClass: 'e-flat e-danger',
isPrimary: true,
},
click: () => {
performDelete();
dialogRef.current?.hide();
},
},
{
buttonModel: { content: 'Cancel', cssClass: 'e-flat' },
click: () => dialogRef.current?.hide(),
},
];
return (
<div id="dialog-target" style={{ position: 'relative' }}>
<button onClick={() => dialogRef.current?.show()}>Delete</button>
<DialogComponent
ref={dialogRef}
header="⚠️ Delete Item"
buttons={buttons}
isModal={true}
target="#dialog-target"
>
This action cannot be undone. Continue?
</DialogComponent>
</div>
);
}Edge Cases
Disabled Buttons
const [isLoading, setIsLoading] = React.useState(false);
const buttons = [
{
buttonModel: {
content: 'Submit',
cssClass: 'e-flat',
isPrimary: true,
isDisabled: isLoading, // Disable while processing
},
click: () => {
setIsLoading(true);
performAction().finally(() => setIsLoading(false));
},
},
];Button with Loading State
const [isSubmitting, setIsSubmitting] = React.useState(false);
const handleSubmit = async () => {
setIsSubmitting(true);
try {
await submitForm();
dialogRef.current?.hide();
} finally {
setIsSubmitting(false);
}
};
const buttons = [
{
buttonModel: {
content: isSubmitting ? 'Submitting...' : 'Submit',
cssClass: 'e-flat',
isPrimary: true,
isDisabled: isSubmitting,
},
click: handleSubmit,
},
];No Buttons (Footer Template Only)
Use footerTemplate if you need complete control and don't want built-in buttons:
const footerTemplate = (
<div style={{ display: 'flex', gap: '10px', justifyContent: 'flex-end', padding: '15px' }}>
<button className="e-control e-btn">Custom 1</button>
<button className="e-control e-btn">Custom 2</button>
</div>
);
<DialogComponent footerTemplate={footerTemplate}>
Content
</DialogComponent>Very Long Button Text
const buttons = [
{
buttonModel: {
content: 'This is a very long button label that might wrap',
cssClass: 'e-flat',
},
click: () => {},
},
];Solution: Set button width
.e-dialog .e-footer .e-btn {
min-width: 100px;
}Dynamic Button Properties
export function DynamicButtons() {
const dialogRef = useRef(null);
const [count, setCount] = React.useState(0);
const buttons = [
{
buttonModel: {
content: `Clicked ${count} times`,
cssClass: 'e-flat',
},
click: () => setCount(count + 1),
},
];
return (
<div id="dialog-target" style={{ position: 'relative' }}>
<button onClick={() => dialogRef.current?.show()}>Show</button>
<DialogComponent
ref={dialogRef}
header="Counter"
buttons={buttons}
target="#dialog-target"
>
Click the button below to count
</DialogComponent>
</div>
);
}Next: Choose another reference topic based on your needs.
Getting Started with React Dialog
Table of Contents
- Installation
- CSS Imports
- Basic Implementation
- Using DialogComponent with Refs
- Show and Hide Methods
- Functional Component Pattern
- Initial Visibility
Installation
Install the required packages from Syncfusion:
npm install @syncfusion/ej2-react-popups @syncfusion/ej2-basePackage Structure
@syncfusion/ej2-react-popups- React wrapper for popups (includes Dialog)@syncfusion/ej2-base- Base styles and utilities
CSS Imports
Import theme CSS in your component. Choose one theme:
Material Theme (Default):
import '@syncfusion/ej2-base/styles/material.css';
import '@syncfusion/ej2-buttons/styles/material.css';
import '@syncfusion/ej2-popups/styles/material.css';Bootstrap Theme:
import '@syncfusion/ej2-base/styles/bootstrap.css';
import '@syncfusion/ej2-buttons/styles/bootstrap.css';
import '@syncfusion/ej2-popups/styles/bootstrap.css';Tailwind Theme:
import '@syncfusion/ej2-base/styles/tailwind.css';
import '@syncfusion/ej2-buttons/styles/tailwind.css';
import '@syncfusion/ej2-popups/styles/tailwind.css';Note: Always import base styles first, then component-specific styles.
Basic Implementation
The simplest Dialog displays content with a header:
import React from 'react';
import { DialogComponent } from '@syncfusion/ej2-react-popups';
import '@syncfusion/ej2-base/styles/material.css';
import '@syncfusion/ej2-popups/styles/material.css';
export default function BasicDialog() {
return (
<div>
<DialogComponent
header="Welcome"
width="400px"
visible={true}
>
<p>This is a simple dialog.</p>
</DialogComponent>
</div>
);
}Key Properties:
header- Dialog title (required)width- Dialog width (default: '330px')visible- Initial visibility (default: false)- Children content becomes the dialog body
Using DialogComponent with Refs
To control dialog visibility programmatically, use refs:
import React, { useRef } from 'react';
import { DialogComponent } from '@syncfusion/ej2-react-popups';
export default function ControlledDialog() {
const dialogRef = useRef(null);
const handleOpen = () => {
dialogRef.current?.show();
};
const handleClose = () => {
dialogRef.current?.hide();
};
return (
<div>
<button onClick={handleOpen} className="e-control e-btn e-primary">
Open Dialog
</button>
<DialogComponent
ref={dialogRef}
header="Contact Form"
width="400px"
visible={false}
>
<p>Email: user@example.com</p>
</DialogComponent>
</div>
);
}Methods:
show()- Display the dialoghide()- Hide the dialog- Access via
dialogRef.current?.method()
Show and Hide Methods
You can control dialog visibility with the ref methods:
const dialogRef = useRef(null);
// Show the dialog
const openDialog = () => {
dialogRef.current?.show();
};
// Hide the dialog
const closeDialog = () => {
dialogRef.current?.hide();
};
// Toggle visibility
const toggleDialog = () => {
if (dialogRef.current) {
// Check if visible by looking at DOM
const isVisible = dialogRef.current.element?.style.display !== 'none';
isVisible ? dialogRef.current.hide() : dialogRef.current.show();
}
};Important: Use optional chaining (?.) because the ref may not be immediately available.
Functional Component Pattern
Modern React uses functional components with hooks:
import React, { useRef, useState } from 'react';
import { DialogComponent } from '@syncfusion/ej2-react-popups';
import '@syncfusion/ej2-base/styles/material.css';
import '@syncfusion/ej2-popups/styles/material.css';
export default function App() {
const dialogRef = useRef(null);
const [formData, setFormData] = useState({ name: '', email: '' });
const handleOpen = () => {
dialogRef.current?.show();
};
const handleClose = () => {
setFormData({ name: '', email: '' });
dialogRef.current?.hide();
};
const handleSubmit = (e) => {
e.preventDefault();
console.log('Submitted:', formData);
handleClose();
};
return (
<div id="dialog-container" style={{ padding: '20px' }}>
<button onClick={handleOpen} className="e-control e-btn e-primary">
Open Form
</button>
<DialogComponent
ref={dialogRef}
header="User Registration"
width="500px"
visible={false}
isModal={true}
showCloseIcon={true}
buttons={[
{
buttonModel: { content: 'Submit', isPrimary: true },
click: handleSubmit,
},
{
buttonModel: { content: 'Cancel' },
click: handleClose,
},
]}
>
<form onSubmit={handleSubmit} style={{ padding: '16px' }}>
<div style={{ marginBottom: '12px' }}>
<label>Name:</label>
<input
type="text"
value={formData.name}
onChange={(e) => setFormData({ ...formData, name: e.target.value })}
style={{ width: '100%', padding: '8px' }}
/>
</div>
<div>
<label>Email:</label>
<input
type="email"
value={formData.email}
onChange={(e) => setFormData({ ...formData, email: e.target.value })}
style={{ width: '100%', padding: '8px' }}
/>
</div>
</form>
</DialogComponent>
</div>
);
}Initial Visibility
Control whether the dialog appears on mount:
// Dialog hidden on load
<DialogComponent header="Hidden" visible={false}>
Content
</DialogComponent>
// Dialog visible on load
<DialogComponent header="Visible" visible={true}>
Content
</DialogComponent>Use visible={false} when you want to show it programmatically with show().
Complete Working Example
import React, { useRef, useState } from 'react';
import { DialogComponent } from '@syncfusion/ej2-react-popups';
import '@syncfusion/ej2-base/styles/material.css';
import '@syncfusion/ej2-buttons/styles/material.css';
import '@syncfusion/ej2-popups/styles/material.css';
export default function App() {
const dialogRef = useRef(null);
const [count, setCount] = useState(0);
const handleOpen = () => {
dialogRef.current?.show();
};
const handleClose = () => {
dialogRef.current?.hide();
};
const handleIncrement = () => {
setCount(count + 1);
};
return (
<div style={{ padding: '20px' }}>
<h1>Dialog Example</h1>
<p>Counter: {count}</p>
<button onClick={handleOpen} className="e-control e-btn e-primary">
Open Dialog
</button>
<DialogComponent
ref={dialogRef}
header="Counter Dialog"
width="350px"
visible={false}
isModal={true}
buttons={[
{
buttonModel: {
content: 'Increment',
isPrimary: true,
cssClass: 'e-flat',
},
click: handleIncrement,
},
{
buttonModel: {
content: 'Close',
cssClass: 'e-flat',
},
click: handleClose,
},
]}
>
<div style={{ padding: '16px' }}>
<p>Current count: {count}</p>
<p>Click Increment to add 1</p>
</div>
</DialogComponent>
</div>
);
}Common Patterns & Edge Cases
Pattern: Dialog in a Target Container
<div id="dialog-target" style={{ position: 'relative', height: '400px' }}>
<DialogComponent
target="#dialog-target"
isModal={true}
>
Dialog appears within target
</DialogComponent>
</div>Edge Case: Ref Not Ready
// Always use optional chaining to safely call methods
dialogRef.current?.show(); // ✓ Safe
dialogRef.current.show(); // ✗ May crash if ref not readyEdge Case: Dialog Content Doesn't Update
// ✓ Correct: State updates trigger re-render
const [isOpen, setIsOpen] = useState(false);
<DialogComponent visible={isOpen}>Content</DialogComponent>
// ✗ Avoid: Only use refs for show/hide methods
// Use state for visible prop to ensure updatesLocalization and Accessibility
Table of Contents
- Localization Overview
- Culture Configuration
- WCAG 2.2 Compliance
- Keyboard Interaction
- ARIA Attributes
- Screen Reader Support
- Focus Management
- Testing Accessibility
Localization Overview
The Dialog component supports localization for:
- Close icon title text
- Button text (if using culture-specific locales)
Supported Locales
The Dialog works with any culture/locale string supported by JavaScript. Common examples:
en- Englishde- Germanfr- Frenches- Spanishpt- Portugueseru- Russianar- Arabiczh- Chineseja- Japaneseko- Koreanhi- Hindiid- Indonesianth- Thaivi- Vietnamesept-BR- Brazilian Portuguesezh-CN- Simplified Chinesezh-TW- Traditional Chinese
Culture Configuration
Basic Culture Setting
import React, { useRef } from 'react';
import { DialogComponent } from '@syncfusion/ej2-react-popups';
import { setCulture } from '@syncfusion/ej2-base';
import './App.css';
export default function App() {
const dialogRef = useRef(null);
// Set culture globally
setCulture('de'); // German
return (
<div id="dialog-target" style={{ position: 'relative' }}>
<button onClick={() => dialogRef.current?.show()}>Open</button>
<DialogComponent
ref={dialogRef}
header="Dialog"
showCloseIcon={true}
target="#dialog-target"
>
Close icon title will be in German
</DialogComponent>
</div>
);
}Culture Switcher
export function LocalizedDialog() {
const dialogRef = useRef(null);
const [culture, setCultureState] = React.useState('en');
const handleCultureChange = (newCulture) => {
setCultureState(newCulture);
setCulture(newCulture);
};
const cultures = ['en', 'de', 'fr', 'es', 'pt', 'ar', 'zh', 'ja'];
return (
<div id="dialog-target" style={{ position: 'relative' }}>
<div style={{ padding: '20px', marginBottom: '20px' }}>
<label>Select Language:</label>
<select
value={culture}
onChange={(e) => handleCultureChange(e.target.value)}
style={{ marginLeft: '10px', padding: '5px' }}
>
{cultures.map((c) => (
<option key={c} value={c}>
{c}
</option>
))}
</select>
</div>
<button onClick={() => dialogRef.current?.show()}>Open Dialog</button>
<DialogComponent
ref={dialogRef}
header={`Dialog (${culture})`}
showCloseIcon={true}
target="#dialog-target"
buttons={[
{
buttonModel: { content: 'OK', isPrimary: true, cssClass: 'e-flat' },
click: () => dialogRef.current?.hide(),
},
]}
>
The close button title is localized to <strong>{culture}</strong>
</DialogComponent>
</div>
);
}Localized Header and Content
The close icon title is automatically localized based on the locale property. You can customize by changing locale:
<DialogComponent
header="Dialog Title"
showCloseIcon={true}
locale="de" // German - close icon title becomes "Schließen"
>
Content
</DialogComponent>Note: closeIconTitle is not a valid DialogComponent property. Localization happens through the locale property.
RTL Support
<div dir="rtl" style={{ textAlign: 'right' }}>
<DialogComponent
header="حوار" // Arabic "Dialog"
showCloseIcon={true}
>
محتوى الحوار {/* Dialog content in Arabic */}
</DialogComponent>
</div>WCAG 2.2 Compliance
The Syncfusion Dialog component is built with accessibility in mind and supports WCAG 2.2 Level AA compliance:
Compliance Features
- ✓ Perceivable: High contrast, semantic HTML
- ✓ Operable: Keyboard navigation, focus management
- ✓ Understandable: Clear labels, logical structure
- ✓ Robust: ARIA support, screen reader compatible
Enable Accessibility
Ensure your implementation follows these patterns:
// ✅ GOOD: Accessible dialog
<DialogComponent
header="Confirmation" // Clear, descriptive header
showCloseIcon={true} // Close button visible
isModal={true} // Clear focus scope
buttons={[
{
buttonModel: {
content: 'OK',
isPrimary: true,
id: 'confirm-btn' // ID for testing
},
click: handleConfirm,
},
]}
>
<p>Clear, descriptive message</p>
</DialogComponent>Keyboard Interaction
The Dialog supports full keyboard navigation:
Tab Navigation
- Tab - Move focus to next element
- Shift + Tab - Move focus to previous element
- Focus cycling - Tab cycles through all dialog elements
<DialogComponent
showCloseIcon={true}
isModal={true}
>
<input placeholder="First input" />
<input placeholder="Second input" />
<button>Action Button</button>
</DialogComponent>Keyboard flow: 1. Tab: Header → Close button 2. Tab: Close button → First input 3. Tab: First input → Second input 4. Tab: Second input → Action button 5. Tab: Action button → Close button (cycles)
Enter Key
- Enter on button - Activates button
- Enter on focused element - Activates it
<DialogComponent buttons={[
{
buttonModel: { content: 'Submit', isPrimary: true },
click: () => console.log('Submitted'),
},
]}>
<input autoFocus /> {/* Gets initial focus */}
</DialogComponent>Escape Key
- Escape - Closes the dialog (if not prevented with closeOnEscape={false})
<DialogComponent
closeOnEscape={true} // Default: true - allows Escape key to close
beforeClose={(e) => {
if (e.isInteracted) {
console.log('Dialog closed via Escape or close button');
}
}}
>
Press Escape to close
</DialogComponent>
// To prevent Escape from closing:
<DialogComponent
closeOnEscape={false}
>
Escape key will not close this dialog
</DialogComponent>Arrow Keys (in Calendar Views)
Not typically used in Dialog, but custom content can handle them.
ARIA Attributes
The Dialog automatically includes ARIA attributes. Enhance with custom attributes:
Dialog ARIA Roles
The DialogComponent automatically includes proper ARIA attributes:
<DialogComponent
header="Confirmation"
// ARIA attributes added automatically:
// role="dialog"
// aria-modal="true"
// header text becomes aria-label
>
Content
</DialogComponent>The header property automatically becomes the aria-label for the dialog.
Labeling Dialog
The header text serves as the ARIA label:
<DialogComponent
header="Are you sure?" // Becomes aria-label
isModal={true}
>
This action will delete the item
</DialogComponent>Button Labeling
Buttons automatically get aria-labels from their content:
const buttons = [
{
buttonModel: {
content: 'Delete', // Becomes aria-label
id: 'delete-btn'
},
click: () => {},
},
];
// HTML output:
// <button id="delete-btn">Delete</button>
// aria-label is auto-generated from contentSemantic Content Structure
Use semantic HTML inside dialog content for better accessibility:
<DialogComponent
header="User Settings"
>
<div>
<h2>Customize Your Settings</h2>
<p>Adjust your preferences below</p>
<form>
<label htmlFor="username">Username:</label>
<input id="username" type="text" />
<label htmlFor="email">Email:</label>
<input id="email" type="email" />
</form>
</div>
</DialogComponent>Note: Don't add aria-label prop directly to DialogComponent - use semantic header and content structure instead.
Screen Reader Support
Testing with Screen Readers
NVDA (Windows - Free):
- Download from https://www.nvaccess.org/
- Start NVDA and navigate dialog with arrow keys
JAWS (Windows):
- Professional screen reader
- Navigate with arrow keys and shortcuts
VoiceOver (macOS/iOS):
- Built-in; enable: System Preferences → Accessibility → VoiceOver
- Navigate with VO (Control + Option) + arrow keys
TalkBack (Android):
- Built-in accessibility feature
- Enable: Settings → Accessibility → TalkBack
Accessible Dialog Example
export function AccessibleDialog() {
const dialogRef = useRef(null);
const buttons = [
{
buttonModel: {
content: 'Confirm',
isPrimary: true,
cssClass: 'e-flat',
id: 'confirm-btn'
},
click: () => {
console.log('Confirmed');
dialogRef.current?.hide();
},
},
{
buttonModel: {
content: 'Cancel',
cssClass: 'e-flat',
id: 'cancel-btn'
},
click: () => dialogRef.current?.hide(),
},
];
return (
<div id="dialog-target" style={{ position: 'relative' }}>
<button
onClick={() => dialogRef.current?.show()}
>
Open Dialog
</button>
<DialogComponent
ref={dialogRef}
header="Confirm Action"
buttons={buttons}
showCloseIcon={true}
isModal={true}
target="#dialog-target"
>
<p>Please confirm that you want to proceed.</p>
</DialogComponent>
</div>
);
}Focus Management
Initial Focus
const dialogRef = useRef(null);
const inputRef = useRef(null);
const handleOpen = () => {
dialogRef.current?.show();
// Move focus to specific element after dialog opens
setTimeout(() => inputRef.current?.focus(), 0);
};
<DialogComponent
ref={dialogRef}
open={handleOpen}
>
<input ref={inputRef} autoFocus placeholder="Gets focus" />
</DialogComponent>Trap Focus in Modal
<DialogComponent
isModal={true}
closeOnEscape={true}
>
{/* Focus is automatically trapped within modal */}
<input placeholder="First" />
<input placeholder="Second" />
<button>Action</button>
</DialogComponent>Return Focus on Close
const triggerButtonRef = useRef(null);
const handleClose = () => {
dialogRef.current?.hide();
// Return focus to trigger button
triggerButtonRef.current?.focus();
};
<>
<button
ref={triggerButtonRef}
onClick={() => dialogRef.current?.show()}
>
Open
</button>
<DialogComponent
ref={dialogRef}
beforeClose={handleClose}
>
Content
</DialogComponent>
</>Testing Accessibility
Manual Testing Checklist
- [ ] Keyboard Navigation: Can you navigate all elements with Tab/Shift+Tab?
- [ ] Escape Key: Does Escape close the dialog?
- [ ] Enter Key: Do buttons activate with Enter?
- [ ] Focus Visible: Is focus indicator clearly visible?
- [ ] Initial Focus: Does focus go to appropriate element on open?
- [ ] Modal Trap: Does Tab cycle within modal, not parent?
- [ ] Labels: Does every control have clear label/text?
- [ ] Color: Is content visible without relying on color alone?
Automated Testing with Axe
npm install --save-dev @axe-core/reactimport { axe } from '@axe-core/react';
export function AccessibilityTest() {
const dialogRef = useRef(null);
React.useEffect(() => {
axe(document).then(results => {
if (results.violations.length) {
console.error('Accessibility violations:', results.violations);
}
});
}, []);
return (
<div id="dialog-target">
<DialogComponent ref={dialogRef}>
Content to test
</DialogComponent>
</div>
);
}Testing with Jest and Testing Library
import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
test('Dialog is keyboard accessible', async () => {
const user = userEvent.setup();
render(
<DialogComponent header="Test">
<button>Action</button>
</DialogComponent>
);
// Tab to button
await user.keyboard('{Tab}');
expect(screen.getByRole('button', { name: /Action/i })).toHaveFocus();
// Press Enter
await user.keyboard('{Enter}');
// Verify action occurred
});Best Practices Summary
✅ DO
- Use semantic HTML in dialog content
- Provide clear, descriptive headers
- Include close button (showCloseIcon={true})
- Support keyboard navigation
- Test with actual screen readers
- Use ARIA labels for custom content
- Manage focus appropriately
- Provide high contrast colors
❌ DON'T
- Use color alone to convey information
- Make interactive elements too small
- Trap keyboard focus in modeless dialogs
- Use auto-playing audio/video
- Disable default keyboard shortcuts
- Create nested focus traps
- Forget to test on real devices
Next: Choose another reference topic based on your needs.
Modal vs Modeless Dialog
Table of Contents
- Modal Dialog
- Modeless Dialog
- Comparison
- Choosing the Right Mode
- Overlay Customization
- Focus Management
- Examples
Modal Dialog
A modal dialog prevents user interaction with the parent application until the dialog is closed. It displays an overlay (backdrop) behind the dialog.
Basic Modal Example
import React, { useRef } from 'react';
import { DialogComponent } from '@syncfusion/ej2-react-popups';
import './App.css';
export default function App() {
const dialogRef = useRef(null);
const buttons = [
{
buttonModel: { content: 'OK', isPrimary: true, cssClass: 'e-flat' },
click: () => dialogRef.current?.hide(),
},
{
buttonModel: { content: 'Cancel', cssClass: 'e-flat' },
click: () => dialogRef.current?.hide(),
},
];
return (
<div id="dialog-target" style={{ position: 'relative', height: '500px' }}>
<h1>Modal Dialog Example</h1>
<button onClick={() => dialogRef.current?.show()} className="e-btn">
Open Modal
</button>
{/* Modal dialog - user cannot interact with content behind */}
<DialogComponent
ref={dialogRef}
header="Important Decision"
buttons={buttons}
isModal={true}
target="#dialog-target"
showCloseIcon={true}
>
<p>This is a modal dialog. You must respond before continuing.</p>
</DialogComponent>
</div>
);
}Key Characteristics
- Overlay visible: Dark/semi-transparent backdrop blocks interaction
- Focus trapped: User cannot access parent content
- Required response: Dialog must be closed to continue
- Blocking behavior: Parent interaction blocked until dialog closes
Use Cases
- Confirmation dialogs ("Are you sure?")
- Critical warnings or errors
- Form submission required
- Security confirmations (delete, logout)
- License acceptance
Modeless Dialog
A modeless dialog allows users to interact with the parent application while the dialog is open. No overlay is displayed.
Basic Modeless Example
import React, { useRef } from 'react';
import { DialogComponent } from '@syncfusion/ej2-react-popups';
import './App.css';
export default function App() {
const dialogRef = useRef(null);
return (
<div id="dialog-target" style={{ position: 'relative', height: '500px' }}>
<h1>Modeless Dialog Example</h1>
<button onClick={() => dialogRef.current?.show()} className="e-btn">
Open Modeless
</button>
{/* Modeless dialog - user CAN interact with content behind */}
<DialogComponent
ref={dialogRef}
header="Floating Window"
isModal={false}
target="#dialog-target"
showCloseIcon={true}
allowDragging={true}
position={{ X: 100, Y: 100 }}
>
<p>This is modeless. Click elements in the background while this is open.</p>
</DialogComponent>
</div>
);
}Key Characteristics
- No overlay: Background is fully visible
- Interaction allowed: User can click parent content
- Floating window: Dialog floats on top like a window
- Non-blocking: Dialog doesn't prevent other actions
Use Cases
- Help/information windows
- Tool palettes or docking windows
- Real-time previews
- Settings that don't require immediate action
- Draggable floating panels
- Chat windows
Comparison
| Feature | Modal | Modeless |
|---|---|---|
| Overlay | Yes (dark backdrop) | No |
| Parent interaction | Blocked | Allowed |
| Close required | Yes (must respond) | Optional (can ignore) |
| Use case | Confirmations, alerts, critical decisions | Tools, helpers, reference windows |
| Typical behavior | Dialog focuses attention | Secondary information |
| Draggable | Usually not | Commonly yes |
| Multiple open | Typically one | Multiple possible |
Choosing the Right Mode
Use Modal if:
- User must make a decision before continuing
- Action is destructive or irreversible
- Requires acknowledgment or consent
- Data entry/form submission needed
Use Modeless if:
- Information is supplementary
- User should maintain context with parent
- Tool or palette window
- Help/reference content
- Real-time collaboration or preview needed
Decision Flowchart
Does the user NEED to respond?
├─ YES → Modal (e.g., "Confirm deletion?")
└─ NO → Modeless (e.g., "Tips & Tricks")
Is it a critical action?
├─ YES → Modal (e.g., security warning)
└─ NO → Modeless (e.g., search result)
Can user ignore this?
├─ YES → Modeless (e.g., help window)
└─ NO → Modal (e.g., form submission)Overlay Customization
Modal Overlay Styling
/* Change overlay color and opacity */
.e-dlg-overlay {
background-color: rgba(0, 0, 0, 0.7);
opacity: 0.8;
}
/* Lighter overlay */
.e-dlg-overlay {
background-color: rgba(100, 100, 255, 0.3);
}
/* Custom blur effect */
.e-dlg-overlay::before {
backdrop-filter: blur(2px);
}Remove Overlay for Custom Styling
<DialogComponent
isModal={true}
className="custom-modal"
>
Content
</DialogComponent>.custom-modal ~ .e-dlg-overlay {
background: none;
}Focus Management
Modal - Automatic Focus Trapping
When modal dialog opens, focus is automatically managed:
- Initial focus goes to first focusable element
- Tab/Shift+Tab cycles through dialog elements
- Cannot tab to parent elements
- Focus returns to trigger button on close
<DialogComponent
isModal={true}
showCloseIcon={true}
>
<input autoFocus placeholder="Focused on open" />
</DialogComponent>Initial Focus Element
const dialogRef = useRef(null);
const handleOpen = () => {
dialogRef.current?.show();
// Move focus to specific element
setTimeout(() => {
document.querySelector('.dialog-input')?.focus();
}, 0);
};
<DialogComponent
ref={dialogRef}
open={handleOpen}
>
<input className="dialog-input" placeholder="Gets focus" />
</DialogComponent>Modeless - Preserve Parent Focus
In modeless dialogs, focus remains on parent:
<DialogComponent
isModal={false}
allowDragging={true}
>
{/* User can click inputs behind this dialog */}
<p>Reference information</p>
</DialogComponent>Examples
Example 1: Confirmation Dialog (Modal)
export function ConfirmDialog() {
const dialogRef = useRef(null);
const [itemToDelete, setItemToDelete] = useState(null);
const confirmDelete = (item) => {
setItemToDelete(item);
dialogRef.current?.show();
};
const handleConfirm = () => {
console.log('Deleting:', itemToDelete);
dialogRef.current?.hide();
};
const buttons = [
{
buttonModel: { content: 'Delete', isPrimary: true, cssClass: 'e-flat e-danger' },
click: handleConfirm,
},
{
buttonModel: { content: 'Cancel', cssClass: 'e-flat' },
click: () => dialogRef.current?.hide(),
},
];
return (
<div id="dialog-target" style={{ position: 'relative' }}>
<button onClick={() => confirmDelete('Item 1')}>Delete Item</button>
<DialogComponent
ref={dialogRef}
header="Confirm Deletion"
buttons={buttons}
isModal={true}
target="#dialog-target"
>
Are you sure you want to delete <strong>{itemToDelete}</strong>?
</DialogComponent>
</div>
);
}Example 2: Floating Tool (Modeless)
export function FloatingTool() {
const dialogRef = useRef(null);
return (
<div id="dialog-target" style={{ position: 'relative', height: '600px' }}>
<div style={{ padding: '20px' }}>
<h1>Main Content Area</h1>
<p>You can interact with this while the tool window is open</p>
<input type="text" placeholder="Try typing here" style={{ padding: '8px' }} />
</div>
<button onClick={() => dialogRef.current?.show()} className="e-btn">
Open Tool
</button>
<DialogComponent
ref={dialogRef}
header="Color Picker"
isModal={false}
allowDragging={true}
enableResize={true}
resizeHandles={['All']}
position={{ X: 300, Y: 100 }}
target="#dialog-target"
width="250px"
>
<div style={{ padding: '10px' }}>
<input type="color" style={{ width: '100%' }} />
</div>
</DialogComponent>
</div>
);
}Example 3: Alert (Modal, Single Button)
<DialogComponent
isModal={true}
header="Alert"
buttons={[
{
buttonModel: { content: 'OK', isPrimary: true, cssClass: 'e-flat' },
click: () => dialogRef.current?.hide(),
},
]}
>
<p>Important update: Your session expires in 5 minutes.</p>
</DialogComponent>Edge Cases
Multiple Modal Dialogs
When opening multiple modals, each should have its own target:
<div id="dialog-target" style={{ position: 'relative' }}>
{/* First modal */}
<DialogComponent
ref={dialog1Ref}
isModal={true}
target="#dialog-target"
zIndex={2000}
>
Parent dialog
<button onClick={() => dialog2Ref.current?.show()}>Open Child</button>
</DialogComponent>
{/* Second modal - higher z-index */}
<DialogComponent
ref={dialog2Ref}
isModal={true}
target="#dialog-target"
zIndex={2001}
>
Child dialog - appears on top
</DialogComponent>
</div>Modeless with Multiple Instances
// Each tool window is independent
<DialogComponent isModal={false} position={{ X: 50, Y: 50 }} />
<DialogComponent isModal={false} position={{ X: 350, Y: 50 }} />
<DialogComponent isModal={false} position={{ X: 50, Y: 350 }} />Next: Choose another reference topic based on your needs.
Templates and Content
Table of Contents
- Header Template
- Content Management
- Footer Templates
- Custom HTML Content
- Dynamic Updates
- Close Icon Customization
- Edge Cases
Header Template
The header is the top section of the dialog. It can be text or custom JSX.
Simple Text Header
<DialogComponent
header="Dialog Title"
showCloseIcon={true}
>
Content
</DialogComponent>Custom Header JSX
import React, { useRef } from 'react';
import { DialogComponent } from '@syncfusion/ej2-react-popups';
import './App.css';
export default function App() {
const dialogRef = useRef(null);
// Custom header component
const customHeader = (
<div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center' }}>
<span>📝 Edit Profile</span>
<span style={{ fontSize: '12px', color: '#999' }}>Step 1 of 3</span>
</div>
);
return (
<div id="dialog-target" style={{ position: 'relative' }}>
<button onClick={() => dialogRef.current?.show()}>Edit</button>
<DialogComponent
ref={dialogRef}
header={customHeader}
showCloseIcon={true}
target="#dialog-target"
>
Content
</DialogComponent>
</div>
);
}Header with Icon
const headerWithIcon = (
<div style={{ display: 'flex', gap: '10px', alignItems: 'center' }}>
<span>⚠️</span>
<span>Warning Message</span>
</div>
);
<DialogComponent header={headerWithIcon}>
Important warning here
</DialogComponent>Styled Header
const styledHeader = (
<div style={{
background: 'linear-gradient(to right, #667eea, #764ba2)',
color: 'white',
padding: '10px',
borderRadius: '4px 4px 0 0'
}}>
Premium Dialog
</div>
);
<DialogComponent header={styledHeader}>
Content
</DialogComponent>Content Management
The content prop accepts text or JSX:
Text Content
<DialogComponent header="Simple">
This is plain text content
</DialogComponent>HTML String Content
<DialogComponent
header="HTML Content"
content="<h2>Hello</h2><p>This is HTML</p>"
>
</DialogComponent>JSX Content
const dialogContent = (
<div style={{ padding: '20px' }}>
<h3>User Profile</h3>
<p>Name: John Doe</p>
<p>Email: john@example.com</p>
<button className="e-btn">Edit</button>
</div>
);
<DialogComponent header="Profile">
{dialogContent}
</DialogComponent>Content as Children
<DialogComponent header="Dialog">
<h3>Title</h3>
<p>Paragraph content</p>
<ul>
<li>Item 1</li>
<li>Item 2</li>
</ul>
</DialogComponent>Footer Templates
Two options for footer: built-in buttons or custom footer template.
Built-in Buttons (Recommended for Simple Cases)
const buttons = [
{
buttonModel: {
content: 'OK',
cssClass: 'e-flat',
isPrimary: true,
},
click: () => console.log('OK clicked'),
},
{
buttonModel: {
content: 'Cancel',
cssClass: 'e-flat',
},
click: () => dialogRef.current?.hide(),
},
];
<DialogComponent buttons={buttons}>
Content
</DialogComponent>Custom Footer Template
Use footerTemplate for complete control:
const footerTemplate = () => {
return (
<div style={{ display: 'flex', gap: '10px', justifyContent: 'flex-end', padding: '15px' }}>
<button className="e-control e-btn">Save</button>
<button className="e-control e-btn">Reset</button>
<button className="e-control e-btn">Cancel</button>
</div>
);
}
<DialogComponent
header="Form"
footerTemplate={footerTemplate}
>
Form content
</DialogComponent>Custom Footer with Forms
export function FormDialog() {
const dialogRef = useRef(null);
const [formData, setFormData] = React.useState({ name: '', email: '' });
const handleSave = () => {
console.log('Saving:', formData);
dialogRef.current?.hide();
};
const footerTemplate = () => {
return (
<div style={{ display: 'flex', gap: '10px', justifyContent: 'flex-end', padding: '15px' }}>
<button
className="e-control e-btn e-primary"
onClick={handleSave}
>
Save
</button>
<button
className="e-control e-btn"
onClick={() => dialogRef.current?.hide()}
>
Cancel
</button>
</div>
);
}
return (
<div id="dialog-target" style={{ position: 'relative' }}>
<button onClick={() => dialogRef.current?.show()}>Open</button>
<DialogComponent
ref={dialogRef}
header="User Form"
footerTemplate={footerTemplate}
target="#dialog-target"
>
<div style={{ padding: '20px' }}>
<div style={{ marginBottom: '15px' }}>
<label>Name:</label>
<input
type="text"
className="e-input"
value={formData.name}
onChange={(e) => setFormData({ ...formData, name: e.target.value })}
/>
</div>
<div>
<label>Email:</label>
<input
type="email"
className="e-input"
value={formData.email}
onChange={(e) => setFormData({ ...formData, email: e.target.value })}
/>
</div>
</div>
</DialogComponent>
</div>
);
}Buttons vs Footer Template
| Aspect | Buttons | Footer Template |
|---|---|---|
| Simplicity | Simple, one-line | Requires JSX |
| Styling | Limited | Full control |
| Multiple Buttons | Good | Better |
| Custom Layout | Limited | Excellent |
| Use Case | OK/Cancel dialogs | Complex footers |
Important: Cannot use both buttons and footerTemplate at the same time.
Custom HTML Content
Rendering Rich Content
const richContent = (
<div style={{ padding: '20px' }}>
<h3>🎉 Congratulations!</h3>
<p>You've completed the task.</p>
<div style={{
background: '#f0f9ff',
padding: '10px',
borderLeft: '4px solid #0ea5e9',
marginTop: '10px'
}}>
<strong>Reward:</strong> +100 points
</div>
</div>
);
<DialogComponent header="Success" isModal={true}>
{richContent}
</DialogComponent>Embedding Images
const contentWithImage = (
<div style={{ textAlign: 'center', padding: '20px' }}>
<img
src="https://example.com/image.png"
alt="Illustration"
style={{ maxWidth: '100%', height: 'auto', marginBottom: '15px' }}
/>
<h3>Feature Highlight</h3>
<p>Check out this new capability</p>
</div>
);
<DialogComponent header="What's New">
{contentWithImage}
</DialogComponent>Forms in Content
const formContent = (
<form style={{ padding: '20px' }}>
<div style={{ marginBottom: '15px' }}>
<label>Username</label>
<input
type="text"
className="e-input"
placeholder="Enter username"
style={{ width: '100%', marginTop: '5px' }}
/>
</div>
<div style={{ marginBottom: '15px' }}>
<label>Password</label>
<input
type="password"
className="e-input"
placeholder="Enter password"
style={{ width: '100%', marginTop: '5px' }}
/>
</div>
</form>
);
<DialogComponent header="Login">
{formContent}
</DialogComponent>Dynamic Updates
Update Content on State Change
export function DynamicDialog() {
const dialogRef = useRef(null);
const [message, setMessage] = React.useState('Loading...');
const [status, setStatus] = React.useState('loading');
React.useEffect(() => {
const timer = setTimeout(() => {
setMessage('✅ Operation completed successfully!');
setStatus('success');
}, 2000);
return () => clearTimeout(timer);
}, []);
const statusColor = status === 'success' ? '#10b981' : '#f59e0b';
return (
<div id="dialog-target" style={{ position: 'relative' }}>
<button onClick={() => dialogRef.current?.show()}>Start</button>
<DialogComponent
ref={dialogRef}
header="Processing"
isModal={true}
target="#dialog-target"
>
<div style={{ padding: '20px', textAlign: 'center', color: statusColor }}>
{message}
</div>
</DialogComponent>
</div>
);
}Update Header Dynamically
export function DynamicHeader() {
const dialogRef = useRef(null);
const [step, setStep] = React.useState(1);
const headerText = `Wizard - Step ${step} of 3`;
const goNext = () => {
if (step < 3) setStep(step + 1);
else dialogRef.current?.hide();
};
return (
<div id="dialog-target" style={{ position: 'relative' }}>
<button onClick={() => dialogRef.current?.show()}>Start Wizard</button>
<DialogComponent
ref={dialogRef}
header={headerText}
buttons={[
{
buttonModel: { content: 'Next', isPrimary: true, cssClass: 'e-flat' },
click: goNext,
},
{
buttonModel: { content: 'Cancel', cssClass: 'e-flat' },
click: () => dialogRef.current?.hide(),
},
]}
target="#dialog-target"
>
<div style={{ padding: '20px' }}>
<h3>Step {step}</h3>
{step === 1 && <p>Select your preferences</p>}
{step === 2 && <p>Confirm your selection</p>}
{step === 3 && <p>Almost done!</p>}
</div>
</DialogComponent>
</div>
);
}Close Icon Customization
Show/Hide Close Icon
// Show close icon
<DialogComponent showCloseIcon={true}>
Click X to close
</DialogComponent>
// Hide close icon (default)
<DialogComponent showCloseIcon={false}>
No close button available
</DialogComponent>Customize Close Icon Title
<DialogComponent
showCloseIcon={true}
locale="en-US" // Close icon title is auto-localized based on locale
>
Content
</DialogComponent>Note: The close icon title is automatically localized. For example, with locale="de" it displays "Schließen", with locale="fr" it displays "Fermer", etc. Set the locale property to control both content and UI text localization.
Styled Close Icon
/* CSS to style close icon */
.e-dialog .e-btn-icon.e-icon-dlg-close {
font-size: 18px;
color: #dc2626;
}
.e-dialog .e-btn-icon.e-icon-dlg-close:hover {
color: #991b1b;
}Custom Close Button in Header
const headerWithCustomClose = (
<div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', padding: '10px' }}>
<span>Custom Header</span>
<button
onClick={() => dialogRef.current?.hide()}
style={{ background: 'none', border: 'none', cursor: 'pointer', fontSize: '20px' }}
>
✕
</button>
</div>
);
<DialogComponent header={headerWithCustomClose} showCloseIcon={false}>
Content with custom close
</DialogComponent>Edge Cases
Empty Header
<DialogComponent header="">
Content with no header area
</DialogComponent>Very Long Header
<DialogComponent header="This is a very long header that might wrap to multiple lines if the dialog is not wide enough">
Content
</DialogComponent>Solution: Set width explicitly
<DialogComponent
header="Very long header..."
width="600px"
>
Content
</DialogComponent>Content Overflow
// Content that exceeds dialog height
<DialogComponent
header="Scrollable Content"
height="300px"
>
<div>
{/* Many items causing overflow */}
{Array.from({ length: 50 }).map((_, i) => (
<p key={i}>Item {i + 1}</p>
))}
</div>
</DialogComponent>CSS to handle overflow:
.e-dialog .e-dlg-content {
overflow-y: auto;
max-height: 300px;
}HTML Injection Safety
When using string content, ensure it's safe:
// ❌ UNSAFE - Never do this with user input
const userInput = "<img src=x onerror='alert(\"XSS\")'>";
<DialogComponent content={userInput} />
// ✅ SAFE - Use JSX instead
<DialogComponent>
{userInput} {/* Automatically escaped */}
</DialogComponent>
// ✅ SAFE - If HTML needed, sanitize first
import DOMPurify from 'dompurify';
const clean = DOMPurify.sanitize(userInput);
<DialogComponent content={clean} />Dynamic Content Loading
export function AsyncContent() {
const dialogRef = useRef(null);
const [content, setContent] = React.useState('Loading...');
const loadContent = async () => {
dialogRef.current?.show();
try {
const response = await fetch('/api/data');
const data = await response.json();
setContent(data.message);
} catch (error) {
setContent('Error loading content');
}
};
return (
<div>
<button onClick={loadContent}>Load</button>
<DialogComponent
ref={dialogRef}
header="Content"
>
{content}
</DialogComponent>
</div>
);
}Next: Choose another reference topic based on your needs.