About

P11FloatingPanel Component

The P11FloatingPanel is a highly customizable, native HTML/CSS-based modal window designed to float independently on the screen. Unlike traditional modals, it can remain open alongside other interactive elements or modals, making it ideal for contextual help, auxiliary tools, or persistent information displays.
Note: This component offers drag-and-drop functionality, dynamic Z-index management to bring it to the front on click, and requires a unique <code>Id</code> for proper JavaScript interop. It uses its own CSS classes and does not rely on Bootstrap JavaScript.


P11FloatingPanel Component Examples

These examples demonstrate various configurations and functionalities of the P11FloatingPanel component, showcasing its flexibility for different use cases.

Create Panel at Specific Coordinates

Enter desired Top and Left coordinates (in pixels) and click 'Create Panel' to display a panel at that exact position. By default, it will appear at (100, 100).

Implementation


<EditForm Model="@specificPanelInputModel" OnValidSubmit="@CreateSpecificPositionPanel">
    <DataAnnotationsValidator />
    <ValidationSummary />

    <div class="row mb-3">
        <div class="col-md-6">
            <P11Input Label="Top Coordinate (px)"
                      @bind-Value="specificPanelInputModel.TopCoordinate"
                      InputType="InputType.Number"
                      ValidationFor="@(() => specificPanelInputModel.TopCoordinate)" />
        </div>
        <div class="col-md-6">
            <P11Input Label="Left Coordinate (px)"
                      @bind-Value="specificPanelInputModel.LeftCoordinate"
                      InputType="InputType.Number"
                      ValidationFor="@(() => specificPanelInputModel.LeftCoordinate)" />
        </div>
    </div>
    <button type="submit" class="btn btn-success me-2">
        <i class="bi bi-geo-alt"></i> Create Panel at Coordinates
    </button>
</EditForm>

<P11FloatingPanel Id="specific-position-panel"
                  Title="Custom Position Panel"
                  Top="@specificPanelState.Top"
                  Left="@specificPanelState.Left"
                  IsVisible="@specificPanelState.IsVisible"
                  OnClose="@(() => specificPanelState.IsVisible = false)">
    <ChildContent>
        <p>This panel was created at the coordinates you specified.</p>
        <p>Current Position: Top @specificPanelState.Top.ToString("F0"), Left @specificPanelState.Left.ToString("F0")</p>
        <button class="btn btn-sm btn-outline-danger mt-2" @onclick="@(() => specificPanelState.IsVisible = false)">Close Panel</button>
    </ChildContent>
</P11FloatingPanel>

public class SpecificPanelInputModel
{
    [Required(ErrorMessage = "Top coordinate is required.")]
    [Range(0, 2000, ErrorMessage = "Top must be between 0 and 2000.")]
    public double TopCoordinate { get; set; } = 100;

    [Required(ErrorMessage = "Left coordinate is required.")]
    [Range(0, 2000, ErrorMessage = "Left must be between 0 and 2000.")]
    public double LeftCoordinate { get; set; } = 100;
}

private SpecificPanelInputModel specificPanelInputModel = new();
private PanelState specificPanelState = new() { Id = "specific-position-panel", Title = "Custom Position Panel", Top = 100, Left = 100, IsVisible = false };

private void CreateSpecificPositionPanel()
{
    specificPanelState.Top = specificPanelInputModel.TopCoordinate;
    specificPanelState.Left = specificPanelInputModel.LeftCoordinate;
    specificPanelState.IsVisible = true;
}


Basic Draggable Panels

Click the button to add new draggable panels one by one. Drag them around and click on them to bring them to the front (dynamic Z-index).

Implementation


<div class="test-controls mb-4">
    <button class="btn btn-primary me-2" @onclick="@AddNewPanel">
        <i class="bi bi-plus-lg"></i> Add New Panel
    </button>
    <button class="btn btn-danger" @onclick="@ClearAllPanels">
        <i class="bi bi-trash"></i> Clear All Panels
    </button>
</div>

<div class="panel-container" style="min-height: 400px; border: 1px dashed #ccc; position: relative;">
    @foreach (var panel in panels)
    {
        <P11FloatingPanel Id="@panel.Id"
                          Title="@panel.Title"
                          Top="@panel.Top"
                          Left="@panel.Left"
                          ZIndex="@panel.ZIndex"
                          IsVisible="@panel.IsVisible"
                          OnPositionUpdate="@(async (pos) => await OnPositionUpdate(panel.Id, pos.Item1, pos.Item2))"
                          OnClose="@(() => OnClose(panel.Id))">
            <ChildContent>
                <h4>@panel.Title</h4>
                <p>Position: Top @panel.Top.ToString("F0"), Left @panel.Left.ToString("F0")</p>
                <p>Z-Index: @panel.ZIndex</p>
                <p>Click on the header to drag, click anywhere on the panel to bring to front.</p>
            </ChildContent>
        </P11FloatingPanel>
    }
</div>

public class PanelState
{
    public string Id { get; set; } = Guid.NewGuid().ToString();
    public string Title { get; set; } = string.Empty;
    public double Top { get; set; }
    public double Left { get; set; }
    public int ZIndex { get; set; } = 1;
    public bool IsVisible { get; set; } = true;
}

private List<PanelState> panels = new();
private int nextPanelNumber = 1;

private void AddNewPanel()
{
    var newPanel = new PanelState
    {
        Id = $"p11-panel-{nextPanelNumber}",
        Title = $"Test Panel #{nextPanelNumber}",
        Top = 100 + (nextPanelNumber * 20), // Offset new panels
        Left = 100 + (nextPanelNumber * 20), // Offset new panels
        ZIndex = 1
    };
    panels.Add(newPanel);
    nextPanelNumber++;
}

private void ClearAllPanels()
{
    panels.Clear();
    nextPanelNumber = 1; // Reset counter for new panels
}


Adding Multiple Predefined Panels

Click the button below to add three predefined panels to the page simultaneously. Each will have a unique position and title.

Implementation


<div class="test-controls mb-4">
    <button class="btn btn-info me-2" @onclick="@AddThreePredefinedPanels">
        <i class="bi bi-three-dots"></i> Add 3 Predefined Panels
    </button>
    <button class="btn btn-danger" @onclick="@ClearAllPanels">
        <i class="bi bi-trash"></i> Clear All Panels
    </button>
</div>

private void AddThreePredefinedPanels()
{
    // Clear existing panels first for a clean demo
    ClearAllPanels();

    panels.Add(new PanelState
    {
        Id = "p11-predefined-1",
        Title = "Predefined Panel 1",
        Top = 50,
        Left = 50,
        ZIndex = 1
    });
    panels.Add(new PanelState
    {
        Id = "p11-predefined-2",
        Title = "Predefined Panel 2",
        Top = 100,
        Left = 150,
        ZIndex = 2
    });
    panels.Add(new PanelState
    {
        Id = "p11-predefined-3",
        Title = "Predefined Panel 3",
        Top = 150,
        Left = 250,
        ZIndex = 3
    });
    // nextPanelNumber is not incremented here as these are "predefined"
}


Panel with Initial Position and Custom Styling

This panel is initialized at the top-left corner (0,0) and has a custom CSS class applied for unique styling. Its initial position is set explicitly.

Implementation


<P11FloatingPanel Id="styled-panel"
                  Title="Styled Panel"
                  Top="0"
                  Left="0"
                  CssClass="custom-panel-style"
                  OnClose="@(() => isStyledPanelVisible = false)"
                  IsVisible="@isStyledPanelVisible">
    <ChildContent>
        <p>This panel has custom styling applied via the <code>CssClass</code> parameter.</p>
        <p>Its initial position is set explicitly.</p>
        <button class="btn btn-sm btn-outline-secondary" @onclick="@(() => isStyledPanelVisible = false)">Close Panel</button>
    </ChildContent>
</P11FloatingPanel>
<button class="btn btn-secondary mt-3" @onclick="@(() => isStyledPanelVisible = true)">Show Styled Panel</button>

private bool isStyledPanelVisible = false; // Initial state for the styled panel


Toggleable Panel Visibility

This panel's visibility is controlled by the <code>IsVisible</code> parameter. Click the button to toggle its display.

Implementation


<button class="btn btn-secondary" @onclick="@ToggleVisibility">
    Toggle Panel Visibility (@(isTogglePanelVisible ? "Currently Visible" : "Currently Hidden"))
</button>
<P11FloatingPanel Id="toggle-panel"
                  Title="Toggle Panel"
                  Top="0"
                  Left="0"
                  IsVisible="@isTogglePanelVisible"
                  OnClose="@(() => isTogglePanelVisible = false)">
    <ChildContent>
        <p>You can show and hide this panel using the button.</p>
        <button class="btn btn-sm btn-outline-secondary" @onclick="@(() => isTogglePanelVisible = false)">Hide Panel</button>
    </ChildContent>
</P11FloatingPanel>

private bool isTogglePanelVisible = false;

private void ToggleVisibility()
{
    isTogglePanelVisible = !isTogglePanelVisible;
}


Panel with Interactive Content

This panel demonstrates how interactive elements can be placed inside a floating panel. The panel can still be dragged and closed.

Implementation


<P11FloatingPanel Id="interactive-panel"
                  Title="Interactive Panel"
                  Top="0"
                  Left="0"
                  OnClose="@(() => isInteractivePanelVisible = false)"
                  IsVisible="@isInteractivePanelVisible">
    <ChildContent>
        <p>Enter some text:</p>
        <input type="text" class="form-control mb-2" @bind="interactivePanelText" placeholder="Type here..." />
        <p>Current Text: @interactivePanelText</p>
        <button class="btn btn-success" @onclick="@(() => interactivePanelText = "Hello World!")">Set Text</button>
        <button class="btn btn-sm btn-outline-danger mt-2" @onclick="@(() => isInteractivePanelVisible = false)">Close Panel</button>
    </ChildContent>
</P11FloatingPanel>
<button class="btn btn-secondary mt-3" @onclick="@(() => isInteractivePanelVisible = true)">Show Interactive Panel</button>

private bool isInteractivePanelVisible = false;
private string interactivePanelText = "Initial Text";




Component API

Parameter Type Default Description
Id Required string string.Empty Gets or sets the unique HTML 'id' attribute for the panel's root element. This is crucial for JavaScript interop to identify and manipulate the panel.
Title string \"Floating Panel\" Gets or sets the title text displayed in the panel's header.
Top double 100 Gets or sets the initial vertical position (top coordinate in pixels) of the panel. This value is updated internally when the panel is dragged.
Left double 100 Gets or sets the initial horizontal position (left coordinate in pixels) of the panel. This value is updated internally when the panel is dragged.
ZIndex int 1 Gets or sets the initial CSS z-index for the panel. This value is updated dynamically by JavaScript when the panel is clicked to bring it to the front.
IsVisible bool true Gets or sets a value indicating whether the panel is currently visible. Setting this to <code>false</code> will hide the panel.
CssClass string? null Gets or sets an optional CSS class string to be applied to the panel's root element.
ChildContent RenderFragment? null Gets or sets the content to be rendered inside the panel's body.
Events
OnPositionUpdate EventCallback<Tuple<double, double>> - An EventCallback that is invoked when the panel's position changes due to dragging. The callback receives a Tuple<double, double> containing the new Top and Left coordinates.
OnClose EventCallback - An EventCallback that is invoked when the panel's close button is clicked. This can be used to set IsVisible to false or remove the panel from a list.




An unhandled error has occurred. Reload 🗙