Surfaces
ModalService
BitModalService shows a BitModal with any content from anywhere in the app - a service, a view model, a handler - rather than from the markup of the page the modal belongs to. Every modal it shows is rendered by the single BitModalContainer mounted in the layout, and each Show hands back a reference: it carries the content component, closes the modal, completes with the result the modal was answered with, and says whether the user was the one who closed it. The modal around the content is customized with a BitModalParameters, which covers the same ground as the BitModal parameters and adds the two things only a service can offer - a guard that turns down a close, and the policy for what happens when the app navigates away. Modals close on navigation by default, survive it when asked to, and can be shown persistent so they outlive the container that renders them.
Notes
A BitModalContainer must be mounted once, in the layout, for the shown modals to render - a modal shown with no container is not rendered, and the service reports that through the logger. Register the service as Scoped on Blazor Server, where a singleton would be shared between circuits; a singleton is only safe for the single-user hosting models (WebAssembly and Hybrid).
The container takes a ModalParameters of its own, which every modal it renders starts from and each modal can override - the place for the house style: a maximum width, a close button, a position.
Usage
Every example is live. Open its code to see exactly what produced the component running underneath.
Basic
Header & Footer
Awaiting a result
Reaching the content
Markup as content
Guarding the close
Updating an open modal
Persistent modals
Closing on navigation
What is open
Watching every modal
API
Every parameter, public member, sub-class and enum this component exposes.
BitModalService parameters
| Name | Type | Default value | Description |
|---|---|---|---|
| OnAddModal | event Func<BitModalReference, Task>? | The event for when a new modal gets added through calling the Show method. | |
| OnCloseModal | event Func<BitModalReference, Task>? | The event for when a modal gets removed through calling the Close method. | |
| IsContainerAvailable | bool | Whether a BitModalContainer is currently mounted for this service, i.e. whether a Show call right now would actually render its modal. It reflects live state rather than registration in DI. | |
| OpenModals | IReadOnlyList<BitModalReference> | A snapshot of the modals this service currently has open, in the order they were opened. It holds what the mounted container renders, plus the persistent modals that are still waiting for a container to mount. | |
| GetModal | BitModalReference? (string? id) | The open modal with the given id, or null when there is none - it was closed, or the id belongs to another service. | |
| Close | Task (BitModalReference modal) | Closes an already opened modal using its reference, with a null result. This is the application closing the modal, so the CanClose guard is not asked. | |
| Close | Task (BitModalReference modal, object? result) | Closes an already opened modal using its reference, with the result its Result task completes with. The CanClose guard is not asked. | |
| TryClose | Task<bool> (BitModalReference modal, object? result) | Asks a modal to close and reports whether it did: a modal whose CanClose guard turns the close down stays open and this answers false. | |
| CloseAll | Task | Closes every modal this service currently has open, each with a null result. The CanClose guards are not asked. | |
| Refresh | Task (BitModalReference? modal) | Re-renders the open modals, invalidating their memoized merged parameters. Call it after mutating modal parameters in place, which doesn't change any object reference and is therefore not detected on its own. Without an argument it refreshes every open modal. | |
| Show | Task<BitModalReference> (Dictionary<string, object>? parameters) | Shows a new BitModal with a custom component with parameters as its content. | |
| Show | Task<BitModalReference> (BitModalParameters? modalParameters) | Shows a new BitModal with a custom component as its content with custom parameters for the modal. | |
| Show | Task<BitModalReference> (Dictionary<string, object>? parameters, BitModalParameters? modalParameters, bool persistent) | Shows a new BitModal with a custom component as its content with custom parameters for the custom component and the modal. A persistent modal survives a container remount and is injected into the next container that mounts. | |
| Show | Task<BitModalReference> (Type componentType, Dictionary<string, object>? parameters, BitModalParameters? modalParameters, bool persistent) | Shows a new BitModal with a component whose type is only known at run time as its content, for the callers that pick their content from a map or a route. Throws an ArgumentException for a type that is not a Blazor component. | |
| Show | Task<BitModalReference> (RenderFragment content, BitModalParameters? modalParameters, bool persistent) | Shows a new BitModal with the given markup as its content, for the content that is not worth a component of its own. The reference's Content stays null for such a modal, since markup is not a component instance. | |
| Show | Task<BitModalReference> (Func<BitModalReference, Dictionary<string, object>?> parametersFactory, BitModalParameters? modalParameters, bool persistent) | Shows a new BitModal, building the content component's parameters from a factory that receives the modal reference. Use this overload when a parameter needs the reference itself, such as an OnClose callback that closes this very modal. |
BitModalReference properties
The handle a Show call hands back: what the modal is, what it answered with, and the ways to close it.
| Name | Type | Default value | Description |
|---|---|---|---|
| Id | string | The unique id of the shown modal. | |
| Content | object? | null | The instance of the component rendered as the content of the modal. It is captured while the modal is rendered, which is after the Show call returns, so it is still null immediately afterwards. |
| IsClosed | bool | false | Whether this modal has already been closed. A reference is never reused, so once set it stays set. |
| IsDismissed | bool | false | Whether the modal was closed by the user - the close button, the overlay, the Escape key - rather than by the application. It is what tells a modal that was walked away from apart from one answered with nothing, which the Result alone cannot. |
| Persistent | bool | false | Whether the modal survives a container remount and is injected into the next container that mounts. |
| Parameters | BitModalParameters? | null | The parameters the modal is shown with, before they are merged with the container's own. |
| Result | Task<object?> | Completes when the modal is closed, with the value it was closed with - null for a modal that was dismissed rather than answered. | |
| Rendered | Task<bool> | Completes with true once a container has rendered the modal, and with false for a modal that was closed before it ever rendered - one shown while no container was mounted, or closed in the same breath it was shown. | |
| Close | Task | Closes the modal without a result. The CanClose guard is not asked. | |
| CloseWith | Task (object? result) | Closes the modal with the given result, which is what its Result task completes with. The CanClose guard is not asked. | |
| TryClose | Task<bool> (object? result) | Asks the modal to close and reports whether it did: a modal whose CanClose guard turns the close down stays open and this answers false. | |
| Dismiss | Task<bool> | Closes the modal as a dismissal - the way the close button, the overlay and the Escape key close it - which asks the CanClose guard and marks the reference as dismissed. The content's own cancel action. | |
| Update | Task (BitModalParameters? parameters) | Replaces the parameters the modal is shown with and re-renders it. The whole set is replaced rather than merged. | |
| GetResult<T> | Task<T?> | The result the modal was closed with, cast to T - the type's default for a modal that was dismissed or answered with something else. | |
| GetContentAsync<T> | Task<T?> | The component rendered as the content, cast to T, waiting for the modal to be rendered first. The type's default for a modal that never rendered or whose content is markup. |
BitModalParameters properties
The set of options a modal is shown with. Every parameter of the BitModal component has a nullable counterpart here (null meaning "not set", so the modal's own default or the container's value is used), plus the two options only a service can offer:
| Name | Type | Default value | Description |
|---|---|---|---|
| CanClose | Func<Task<bool>>? | null | Asked before the user closes the modal - the close button, the overlay, the Escape key - and before an explicit TryClose. Answering false keeps the modal open. Close, CloseWith, CloseAll and a close on navigation are the application closing the modal and do not ask it. Only the guard on the modal's own parameters is asked, not one on the container's. |
| CloseOnNavigation | bool? | null | Whether the modal closes when the app navigates somewhere else, which it does by default. Only a change of path counts; a query string or a fragment changed on the same page does not. Set it to false for the modals that outlive a route change. |
Feedback
Found a mistake, a gap, or something that could be clearer? Every page and every component is one click from its source.