P11FloatingPanel Component
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.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. |