A Blazor Modal Component Based on Bootstrap 5

According to all that I show thee, after the pattern of the tabernacle and the pattern of all the instruments thereof, even so shall ye make it.
כְּכֹל אֲשֶׁר אֲנִי מַרְאֶה אוֹתְךָ אֵת תַּבְנִית הַמִּשְׁכָּן וְאֵת תַּבְנִית כָּל-כֵּלָיו וְכֵן תַּעֲשׂוּ

Exodus 25:9 uses the Hebrew word תבנית (tavniyt) to describe a pattern or template. The word derives from the root בנה which relates to building (construction).

Source can be found at https://github.com/rlebowitz/Finaltouch.Modal

Demo can be found at https://rlebowitz.github.io/Finaltouch.Modal/

I often need to use a modal control for editing small forms in my applications. While it would be possible to write such a control from scratch, it's much simpler to adapt an existing modal for this purpose. I like using Bootstrap 5 these days so I'm presenting the code for a Blazor version of their modal here.

The Bootstrap 5 modal design includes three subsections; a header, body and footer. The header generally includes a title and as the documentation recommends, a dismiss action (means to close the modal). You can of course, incorporate different header content, but I provide an approach that displays a header if you pass a title value, along with a dismiss action. The Razor code below shows a template that incorporates these features.

  
   <div tabindex="-1" class="modal fade @ModalZoom @ModalClass" style="display: @ModalDisplay" @attributes="AriaAttributes">
    <div class="modal-dialog @ModalScroll @ModalCentered">
        <div class="modal-content">
            @if (Title != null)
            {
                <div class="modal-header">
                    <h5 class="modal-title">@Title</h5>
                    <button class="btn-close" data-dismiss="modal" aria-label="Close" @onclick="Close">
                    </button>
                </div>
            }
            <div class="modal-body">
                @Body
            </div>
            @if (Footer != null)
            {
                <div class="modal-footer">
                    @Footer
                </div>
            }
        </div>
    </div>
</div>

<div class="modal-backdrop fade @ModalClass" style="display: @ModalDisplay"></div>
  
  

Looking at the C# code-behind, you'll see a few useful parameters that can be used to alter the behavior of the modal. You can switch between the "standard" animation where the modal appears to drop vertically into view, or use a zoom-like animation. You can center the dialog within the view, and you can add a scrollbar to the modal itself, provided that the content is sufficiently long, instead of using the scrollbar for the entire viewport that will appear automatically. I thought it would be fun to provide some scrollable content using a Hebrew Ipsum Lorem text generator.

There's very little actual code or logic required in this component. I automatically add the various aria attributes that you would see using the regular Javascript version of the Bootstrap component. One important feature to pay attention to are the Task.Delay() statements I utilize in the Open() and Close() methods. These are used to ensure that you can actually see the animation effects; without the delays the cool animations would have no time to complete their execution.

  
    
using Microsoft.AspNetCore.Components;

namespace Finaltouch.Modal.App.Shared
{
    /// <summary>
    /// A Blazor Modal Template Component
    /// </summary>
    public partial class DialogTemplate
    {
        [Parameter]
        public RenderFragment? Body { get; set; }
        [Parameter]
        public RenderFragment? Footer { get; set; }
        [Parameter]
        public string? Title { get; set; }
        [Parameter]
        public bool UseZoom { get; set; }
        [Parameter]
        public bool Scrollable { get; set; }
        public bool Centered { get; set; } = true;
        private string ModalDisplay { get; set; } = "none";
        private string ModalClass { get; set; } = string.Empty;
        private string ModalZoom => UseZoom ? "modal-zoom" : string.Empty;
        private string ModalScroll => Scrollable ? "modal-dialog-scrollable" : string.Empty;
        private string ModalCentered => (Centered && !Scrollable) ? "modal-dialog-centered" : string.Empty;

        private Dictionary<string, object> AriaAttributes
        {
            get
            {
                var attributes = new Dictionary<string, object>();
                if ("block".Equals(ModalDisplay))
                {
                    attributes.Clear();
                    attributes.Add("aria-modal", "true");
                    attributes.Add("role", "dialog");
                }
                else
                {
                    attributes.Clear();
                    attributes.Add("aria-hidden", "true");
                }
                return attributes;
            }
        }

        public async Task Open()
        {
            ModalDisplay = "block";
            await Task.Delay(200);
            ModalClass = "show";
        }

        public async Task Close()
        {
            ModalClass = string.Empty;
            await Task.Delay(200);
            ModalDisplay = "none";
        }

    }
}

Some of the code and inspiration for this component came from this thread on Stack Overflow. It's worth reading to see how other folks have created modal components based on Bootstrap.

No comments:

Post a Comment