Skip to main content

syncfusion-blazor-toolkit-dialog

Implement Syncfusion Blazor Toolkit SfDialog — modal and modeless windows with buttons, drag, resize, focus trap, ARIA semantics, and animation. USE FOR: confirmation modals, form-in-modal, full-screen dialogs, alert dialogs, settings panels, modals that block the underlying UI, and DialogService-driven dynamic creation. DO NOT USE FOR: brief informational text on hover (use the syncfusion-blazor-toolkit-tooltip skill), non-blocking progress overlays (use syncfusion-blazor-toolkit-notifications / SfSpinner), or as a navigation primitive.

معلومات المصدر

المستودع
syncfusion/blazor-toolkit
آخر نشاط في المصدر
٢٤ أغسطس ٢٠٢٦ في ١١:٤٠
لغة SKILL.md المكتشفة
الإنجليزية
النجوم
٢٠
التفرعات
٩

خيارات التثبيت

يُحدَّد Prompt الذي يراجع المصدر أولًا بشكل افتراضي. يمكنك التبديل إلى أمر مباشر أو تنزيل نسخة محلية.

مراجعة ملفات المصدر

اقرأ SKILL.md وأي ملفات مرافقة يعرضها SkillsMP قبل أن تقرر التثبيت.

مستكشف الملفات
4 ملفات

عرض SKILL.md

SKILL.md
تعليمات المصدر · معاينة للقراءة فقط
license
MIT
name
syncfusion-blazor-toolkit-dialog
description
Implement Syncfusion Blazor Toolkit SfDialog — modal and modeless windows with buttons, drag, resize, focus trap, ARIA semantics, and animation. USE FOR: confirmation modals, form-in-modal, full-screen dialogs, alert dialogs, settings panels, modals that block the underlying UI, and DialogService-driven dynamic creation. DO NOT USE FOR: brief informational text on hover (use the syncfusion-blazor-toolkit-tooltip skill), non-blocking progress overlays (use syncfusion-blazor-toolkit-notifications / SfSpinner), or as a navigation primitive.
metadata
{"author":"Syncfusion Inc","version":"1.0.0"}
# Syncfusion Blazor Toolkit: Dialog (SfDialog) `SfDialog` renders an overlay window that *blocks* the underlying page when modal, or floats alongside it when modeless. It supports a header, body, buttons, drag, resize, animation, and a service for dynamic creation. ## Core Rules 1. **Use `IsModal="true"` for any dialog that requires user input** — the framework installs the focus trap and `aria-modal`. 2. **Bind visibility with `@bind-Visible`, not `Visible=…` alone** — `SfDialog` needs `VisibleChanged` to mirror state. 3. **`DialogButtons` are declarative; one `OnClick` per `DialogButton`.** Use `OnClick="@(() => dialog.Close())"` to dismiss without inverting the state. 4. **`AllowPrerender="false"`** whenever the dialog body depends on interactive content (e.g., JS interop inside the dialog, `EditForm` validation, dynamic data). Default rendering in interactive render modes will double-mount the dialog. 5. **`CloseOnEscape="true"` is the default; re-declaring with the same value is harmless** but pairing with `ShowCloseIcon="true"` is required for mouse-only users to dismiss. 6. **`OnClose` is cancelable** — set `args.Cancel = true` to prevent close, useful for unsaved-changes warnings. `OnClosed` is non-cancelable and runs after dismissal. 7. **Programmatic lifecycle**: use a `@ref` (`SfDialog dlg`) and call `dlg.Show()` / `dlg.Hide()` — do not hand-toggle `bool isVisible` if you need to invoke `OnClose` first. ```razor @using Syncfusion.Blazor.Toolkit.Popups @implements IAsyncDisposable <SfDialog @ref="confirm" @bind-Visible="@_showConfirm" IsModal="true" ShowCloseIcon="true" AllowPrerender="false" CloseOnEscape="true" Header="Confirm" Width="420px" OnClose="OnApproachClose"> <DialogTemplates> <Content> <p>@_message</p> </Content> </DialogTemplates> <DialogButtons> <DialogButton Content="Yes" IsPrimary="true" OnClick="@(() => OnDecideAsync(true))" /> <DialogButton Content="No" OnClick="@(() => OnDecideAsync(false))" /> </DialogButtons> </SfDialog> ``` ## Decision Tree ``` Need a dialog? ├─ Single-shot static content? │ └─ Inline <SfDialog @bind-Visible="…"> ├─ Triggered by code from many places? │ └─ DialogService (see dialog-advanced.md) └─ Multi-step wizard? └─ Inline <SfDialog> + your own step state ``` ## Documentation and Navigation Guide | Need | Read | |---|---| | First modal / project setup | [references/dialog-basics.md](references/dialog-basics.md) | | Properties, events, methods, animation surface (this skill's table-of-truth) | [references/dialog-properties.md](references/dialog-properties.md) | | Service-pattern, dynamic creator, wizard, cascading integration | [references/dialog-advanced.md](references/dialog-advanced.md) | For cross-component decision matrix (dialog vs tooltip vs popover), see [../router/dialog-vs-tooltip-decision-matrix.md](../router/dialog-vs-tooltip-decision-matrix.md). ## Top 5 Properties You'll Use | Property | Why it matters | |---|---| | `@bind-Visible` | Canonical visibility binding (works with `@bind-Visible` + `VisibleChanged`); not `Visible=...` alone | | `IsModal` | Installs `aria-modal` + focus trap; required for any user-input dialog | | `AllowPrerender` | Set `false` whenever the body depends on interactive content (JS interop, `EditForm`, dynamic data) | | `ShowCloseIcon` | Mouse-only users have no other dismiss affordance; pair with `CloseOnEscape="true"` | | `DialogAnimationSettings` / `Animation` | `DialogEffect` enum — pick exactly one (`Fade`/`Zoom`/`Slide*`/`None`) | Full property/event/method/animation reference: [references/dialog-properties.md](references/dialog-properties.md). ## Common Patterns ### Pattern 1 — Inline confirmation modal (delete / unsaved-changes guard) See the **Core Rules** snippet above for a full modal example. ### Pattern 2 — Programmatic lifecycle ```razor @using Syncfusion.Blazor.Toolkit.Popups <SfDialog @ref="dlg" AllowPrerender="false" /> <button @onclick="@(() => dlg.Show())">Open programmatically</button> ``` ## Don'ts | Anti-pattern | Symptom | Fix | |---|---|---| | Nested `<SfDialog>` inside another `<SfDialog>` | Render artifacts on overlay click; z-index collisions; nested focus trap locks browser | Use portals/z-index (inner > outer by ≥1000), or replace outer with stacked steps | | Toggle `@bind-Visible` *and* call `Hide()` for the same dismissal | Second mechanism undoes the first; visuals flicker | Use only one mechanism: bind the bool, or call `Hide()` programmatically | | `CloseOnEscape` used to cancel close | That flag toggles default behaviour; it doesn't intercept | Use the cancelable `OnClose` event with `args.Cancel = true` | | `<SfDialog AllowDragging="true">` with `IsModal="true"` | Conflict — modal sets focus trap; dragging fights focus | Choose: free-form (no focus trap) or modal (no drag); rarely both | | `<SfDialog>` containing `<form>` directly without binding the dialog lifecycle | Submit button doesn't post to the page EditContext model | Use `<EditForm Model="@X" OnValidSubmit="@Save">` inside `DialogTemplates`, and trigger save via button inside the form | | `IsModal="false"` *and* no backdrop for destructive actions | User can click delete triggers elsewhere | `IsModal="true"` plus `ShowCloseIcon="true"` | | `Visible="true"` initial in markup | Dialog opens on first paint — usually unintended auto-pop | Use `@bind-Visible` and toggle from a button | > Don'ts covered by Anti-Pattern Workflows (double-binding, JS in `OnInitialized`, JS in `DialogTemplates`/`OnAfterRenderAsync`, no `DisposeAsync`) are not duplicated here — see the workflows below. ## Anti-Pattern Workflows > **Note:** Snippets below tagged **Bad:** are intentionally minimal — namespace directives (`@using`), DI wiring, and other context are omitted to keep the failure-mode illustration short. The **Correct:** snippets include `@using` directives needed for copy-paste. ### Workflow 1 — Agent copies the dead `onConfirmCallback` snippet **Anti-pattern** (matches an older SKILL.md `Modal Confirmation Dialog` snippet): ```razor <SfDialog @bind-Visible="showConfirm" IsModal="true" Header="Confirmation"> <DialogTemplates><Content><p>@confirmMessage</p></Content></DialogTemplates> <DialogButtons> <DialogButton Content="Yes" IsPrimary="true" OnClick="@OnConfirmYes"/> <DialogButton Content="No" OnClick="@OnConfirmNo"/> </DialogButtons> </SfDialog> @code { private string confirmMessage = ""; private Func<Task> onConfirmCallback; // ❌ assigned, never invoked private async Task OnConfirmYes() { showConfirm = false; /* callback never called */ } } ``` **Why it fails:** `onConfirmCallback` is set by `ShowConfirmation(...)` but the button onclick never invokes it. Pressing "Yes" effectively does nothing. **Correct — `EventCallback<T>`-based:** ```razor @using Syncfusion.Blazor.Toolkit.Popups <SfDialog @bind-Visible="@_showConfirm" IsModal="true" Header="Confirm" AllowPrerender="false" ShowCloseIcon="true"> <DialogTemplates><Content><p>@_message</p></Content></DialogTemplates> <DialogButtons> <DialogButton Content="Yes" IsPrimary="true" OnClick="@(() => Decide(true))"/> <DialogButton Content="No" OnClick="@(() => Decide(false))"/> </DialogButtons> </SfDialog> @code { private bool _showConfirm; private string _message = ""; [Parameter] public EventCallback<bool> OnDecision { get; set; } public void Ask(string message) { _message = message; _showConfirm = true; } private async Task Decide(bool accepted) { _showConfirm = false; await OnDecision.InvokeAsync(accepted); } } ``` Parent wires `@bind-OnDecision` and gets a bool back. ### Workflow 2 — Agent calls `dlg.Show()` from `OnInitialized` **Bad:** ```razor @code { protected override void OnInitialized() { dialog.Show(); } } ``` **Fix:** ```razor @using Syncfusion.Blazor.Toolkit.Popups <SfDialog @ref="dialog" AllowPrerender="false" /> <button @onclick="@(() => dialog.Show())">Open</button> @code { SfDialog? dialog; protected override async Task OnAfterRenderAsync(bool first) { if (first && dialog is not null) await dialog.Show(); } public async ValueTask DisposeAsync() { if (dialog is not null) await dialog.DisposeAsync(); } } ``` ### Workflow 3 — Agent tries JS init inside `DialogTemplates` during prerender **Bad:** ```razor <SfDialog AllowPrerender="true"> <DialogTemplates> <Content> @inject IJSRuntime JS <p>URL: @currentUrl</p> <!-- JS throws on first paint --> </Content> </DialogTemplates> </SfDialog> @code { private string currentUrl; protected override void OnInitialized() { currentUrl = JS.InvokeAsync<string>("getHref").Result; } } ``` **Fix:** ```razor @using Syncfusion.Blazor.Toolkit.Popups <SfDialog AllowPrerender="false"> <DialogTemplates> <Content> @if (_url is null) { <p>Loading…</p> } else { <p>URL: @_url</p> } </Content> </DialogTemplates> </SfDialog> @code { private string? _url; [Inject] private IJSRuntime JS { get; set; } = default!; protected override async Task OnAfterRenderAsync(bool first) { if (first) _url = await JS.InvokeAsync<string>("getHref"); } } ``` ### Workflow 4 — Agent wants a confirmation modal that traps `OnClose` **Correct:** ```razor @using Syncfusion.Blazor.Toolkit.Popups <SfDialog OnClose="@BlockIfDirty" @bind-Visible="@_open"> <DialogTemplates> <Content><p>Save the document?</p></Content> </DialogTemplates> <DialogButtons> <DialogButton Content="Save" OnClick="SaveFirst"/> <DialogButton Content="Discard" OnClick="Discard"/> </DialogButtons> </SfDialog> @code { private bool _dirty; private void BlockIfDirty(BeforeCloseEventArgs e) { e.Cancel = _dirty; // user must explicitly Save or Discard } } ``` **Button vs `OnClose` order:** `DialogButton.OnClick` fires *first*, then the framework attempts the close (which triggers `OnClose`). If `OnClose` sets `args.Cancel = true`, the dialog stays open — but the button's already-run handler still executed. If your "Save" button must complete before the close is decided, do the work inside the button's `OnClick` and *don't* rely on the dialog still being open afterwards. ## Next Steps 1. **First modal:** [references/dialog-basics.md](references/dialog-basics.md) 2. **Service pattern / dynamic creator / wizard:** [references/dialog-advanced.md](references/dialog-advanced.md) 3. **Cross-skill decision matrix:** [../router/dialog-vs-tooltip-decision-matrix.md](../router/dialog-vs-tooltip-decision-matrix.md) **Demo:** https://blazor.syncfusion.com/demos/toolkit/dialogs
عرض على GitHub