P11DrawerNative Component
P11DrawerNative is a lightweight, pure HTML/CSS-based drawer (or offcanvas) component that operates without relying on Bootstrap JavaScript. It provides a highly accessible, customizable slide-out panel, complete with features like overlays, focus trapping, and scroll prevention.P11DrawerNative Component Examples
These examples demonstrate various configurations and functionalities of the P11DrawerNative component, showcasing its flexibility for different use cases.
Drawer from Left (Default, with Title & Close Button and Size)
This is a drawer that slides in from the left. It has a title and a built-in close button. The background does not scroll, and focus is trapped within the drawer. Press ESC to close.
Main Left Drawer
This is a drawer that slides in from the left. It has a title and a built-in close button.
The background does not scroll, and focus is trapped within the drawer. Press ESC to close.
Some random content to test scrolling if the content is too long:
Line 1 in the left drawer.
Line 2 in the left drawer.
Line 3 in the left drawer.
Line 4 in the left drawer.
Line 5 in the left drawer.
Line 6 in the left drawer.
Line 7 in the left drawer.
Line 8 in the left drawer.
Line 9 in the left drawer.
Line 10 in the left drawer.
Line 11 in the left drawer.
Line 12 in the left drawer.
Line 13 in the left drawer.
Line 14 in the left drawer.
Line 15 in the left drawer.
Line 16 in the left drawer.
Line 17 in the left drawer.
Line 18 in the left drawer.
Line 19 in the left drawer.
Line 20 in the left drawer.
Main Left Drawer
This is a drawer that slides in from the left and has size of 450px. It has a title and a built-in close button.
The background does not scroll, and focus is trapped within the drawer. Press ESC to close.
Some random content to test scrolling if the content is too long:
Line 1 in the left drawer.
Line 2 in the left drawer.
Line 3 in the left drawer.
Line 4 in the left drawer.
Line 5 in the left drawer.
Line 6 in the left drawer.
Line 7 in the left drawer.
Line 8 in the left drawer.
Line 9 in the left drawer.
Line 10 in the left drawer.
Line 11 in the left drawer.
Line 12 in the left drawer.
Line 13 in the left drawer.
Line 14 in the left drawer.
Line 15 in the left drawer.
Line 16 in the left drawer.
Line 17 in the left drawer.
Line 18 in the left drawer.
Line 19 in the left drawer.
Line 20 in the left drawer.
Current Status (Left): Closed
Implementation
<h4 class="mb-3">Drawer from Left (Default, with Title & Close Button)</h4>
<p>This is a drawer that slides in from the left. It has a title and a built-in close button. The background does not scroll, and focus is trapped within the drawer. Press ESC to close.</p>
<button class="btn btn-primary" @onclick="() => isDrawerLeftOpen = true">Open Left Drawer</button>
<P11DrawerNative @bind-IsOpen="isDrawerLeftOpen"
Position="DrawerPosition.Left"
HasOverlay="true"
Title="Main Left Drawer"
ShowCloseButton="true"
PreventScroll="true"
EnableFocusTrap="true"
CloseOnOutsideClick="true"
AdditionalAttributes="@(new Dictionary<string, object> { { "id", "drawer-left-main" } })">
<div style="padding: 20px;">
<p>This is a drawer that slides in from the left. It has a title and a built-in close button.</p>
<p>The background does not scroll, and focus is trapped within the drawer. Press ESC to close.</p>
<p>Some random content to test scrolling if the content is too long:</p>
@for (int i = 0; i < 20; i++)
{
<p>Line @(i + 1) in the left drawer.</p>
}
</div>
</P11DrawerNative>
<p>Current Status (Left): @(isDrawerLeftOpen ? "Open" : "Closed")</p>@code {
private bool isDrawerLeftOpen = false;
}Drawer from Right (No Overlay, No Outside Close)
This drawer slides in from the right and has **no** overlay. Clicking outside it will **not** close it. Use the integrated close button or the ESC key.
Right Info Drawer
This drawer slides in from the right and has **no** overlay. Clicking outside it will **not** close it.
Use the integrated close button or the ESC key.
Some random content:
- Item 1
- Item 2
- Item 3
Current Status (Right): Closed
Implementation
<h4 class="mb-3">Drawer from Right (No Overlay, No Outside Close)</h4>
<p>This drawer slides in from the right and has **no** overlay. Clicking outside it will **not** close it. Use the integrated close button or the ESC key.</p>
<button class="btn btn-info" @onclick="() => isDrawerRightOpen = true">Open Right Drawer (no overlay, no outside close)</button>
<P11DrawerNative @bind-IsOpen="isDrawerRightOpen"
Position="DrawerPosition.Right"
HasOverlay="false"
Title="Right Info Drawer"
ShowCloseButton="true"
CloseOnOutsideClick="false"
AdditionalAttributes="@(new Dictionary<string, object> { { "id", "drawer-right-no-overlay" } })">
<div style="padding: 20px;">
<p>This drawer slides in from the right and has **no** overlay. Clicking outside it will **not** close it.</p>
<p>Use the integrated close button or the ESC key.</p>
<p>Some random content:</p>
<ul>
<li>Item 1</li>
<li>Item 2</li>
<li>Item 3</li>
</ul>
<button class="btn btn-warning" @onclick="() => isDrawerRightOpen = false">Internal Close Button (for demo only)</button>
</div>
</P11DrawerNative>
<p>Current Status (Right): @(isDrawerRightOpen ? "Open" : "Closed")</p>@code {
private bool isDrawerRightOpen = false;
}Drawer from Top (Manual Close)
This drawer slides in from the top. The background **can** scroll.
Top Input Drawer
This drawer slides in from the top. The background **can** scroll.
Current Status (Top): Closed
Implementation
<h4 class="mb-3">Drawer from Top (Manual Close)</h4>
<p>This drawer slides in from the top. The background **can** scroll.</p>
<button class="btn btn-warning" @onclick="() => isDrawerTopOpen = true">Open Top Drawer</button>
<P11DrawerNative @bind-IsOpen="isDrawerTopOpen"
Position="DrawerPosition.Top"
Title="Top Input Drawer"
ShowCloseButton="true"
PreventScroll="false"
AdditionalAttributes="@(new Dictionary<string, object> { { "id", "drawer-top-input" } })">
<div style="padding: 20px;">
<p>This drawer slides in from the top. The background **can** scroll.</p>
<input type="text" class="form-control mb-2" placeholder="Text field in drawer" />
<textarea class="form-control" rows="3" placeholder="More text"></textarea>
<button class="btn btn-secondary mt-3" @onclick="() => isDrawerTopOpen = false">Close via internal button</button>
</div>
</P11DrawerNative>
<p>Current Status (Top): @(isDrawerTopOpen ? "Open" : "Closed")</p>@code {
private bool isDrawerTopOpen = false;
}Drawer from Bottom (No Title, with AriaLabel)
This drawer slides in from the bottom. It has no visible Title parameter, but an AriaLabel for screen readers.
Current Status (Bottom): Closed
Implementation
<h4 class="mb-3">Drawer from Bottom (No Title, with AriaLabel)</h4>
<p>This drawer slides in from the bottom. It has no visible <code>Title</code> parameter, but an <code>AriaLabel</code> for screen readers.</p>
<button class="btn btn-danger" @onclick="() => isDrawerBottomOpen = true">Open Bottom Drawer</button>
<P11DrawerNative @bind-IsOpen="isDrawerBottomOpen"
Position="DrawerPosition.Bottom"
AriaLabel="Footnotes and Imprint"
ShowCloseButton="true"
AdditionalAttributes="@(new Dictionary<string, object> { { "id", "drawer-bottom-footer" } })">
<div style="padding: 20px;">
<h5>Important Information</h5>
<p>This drawer has no visible <code>Title</code> parameter, but an <code>AriaLabel</code> for screen readers.</p>
<p>Imprint | Privacy Policy | Contact</p>
<button class="btn btn-outline-danger" @onclick="() => isDrawerBottomOpen = false">Close</button>
</div>
</P11DrawerNative>
<p>Current Status (Bottom): @(isDrawerBottomOpen ? "Open" : "Closed")</p>@code {
private bool isDrawerBottomOpen = false;
}Drawer with Overlay Click Handler & No Development Errors
This drawer closes when the overlay is clicked (in addition to the internal close button). ShowDevelopmentErrors is set to false here.
Overlay Click Test
Click on the overlay to close this drawer and display a message.
Overlay Click Message: No overlay click yet.
Current Status (Overlay Test): Closed
Implementation
<h4 class="mb-3">Drawer with Overlay Click Handler & No Development Errors</h4>
<p>This drawer closes when the overlay is clicked (in addition to the internal close button). <code>ShowDevelopmentErrors</code> is set to <code>false</code> here.</p>
<button class="btn btn-success" @onclick="() => isDrawerOverlayTestOpen = true">Open Drawer with Overlay Handler</button>
<P11DrawerNative @bind-IsOpen="isDrawerOverlayTestOpen"
Position="DrawerPosition.Left"
OnOverlayClick="HandleOverlayTestClick"
Title="Overlay Click Test"
ShowCloseButton="true"
ShowDevelopmentErrors="false"
AdditionalAttributes="@(new Dictionary<string, object> { { "id", "drawer-overlay-test" } })">
<div style="padding: 20px;">
<p>Click on the overlay to close this drawer and display a message.</p>
<button class="btn btn-secondary" @onclick="() => isDrawerOverlayTestOpen = false">Close</button>
</div>
</P11DrawerNative>
<p>Overlay Click Message: @overlayClickMessage</p>
<p>Current Status (Overlay Test): @(isDrawerOverlayTestOpen ? "Open" : "Closed")</p>@code {
private bool isDrawerOverlayTestOpen = false;
private string overlayClickMessage = "No overlay click yet.";
private void HandleOverlayTestClick()
{
overlayClickMessage = $"Overlay clicked at {DateTime.Now:HH:mm:ss}";
}
}Drawer that should trigger an Accessibility Warning
This drawer has no Title, AriaLabel, or AriaLabelledby, and ShowDevelopmentErrors is true (default). When opened, a development warning should be displayed on the page.
This is a drawer that should trigger an accessibility warning. Please look at the page.
Current Status (Accessibility Warning): Closed
Fullscreen Drawer Demo: This drawer is configured with IsFullScreen="true", causing it to cover the entire viewport, regardless of its Position parameter. The drawer will slide in from the top as specified by Position="DrawerPosition.Top".
Fullscreen Drawer
This drawer is in fullscreen mode. Note how it covers the entire screen, even though its Position is set to `Top`.
Current Status (Fullscreen Demo): Closed
Implementation
<h4 class="mb-3">Drawer that should trigger an Accessibility Warning</h4>
<p>This drawer has no Title, AriaLabel, or AriaLabelledby, and <code>ShowDevelopmentErrors</code> is <code>true</code> (default). When opened, a development warning should be displayed on the page.</p>
<button class="btn btn-danger" @onclick="() => isDrawerAccessibilityWarningOpen = true">Open Drawer with Warning</button>
<P11DrawerNative @bind-IsOpen="isDrawerAccessibilityWarningOpen"
Position="DrawerPosition.Left"
HasOverlay="true"
ShowCloseButton="true"
ShowDevelopmentErrors="true"
AdditionalAttributes="@(new Dictionary<string, object> { { "id", "drawer-accessibility-warning" } })">
<div style="padding: 20px;">
<p>This is a drawer that should trigger an accessibility warning. Please look at the page.</p>
<button class="btn btn-secondary" @onclick="() => isDrawerAccessibilityWarningOpen = false">Close</button>
</div>
</P11DrawerNative>
<p>Current Status (Accessibility Warning): @(isDrawerAccessibilityWarningOpen ? "Open" : "Closed")</p>
<br />
<br />
<p>
Fullscreen Drawer Demo: This drawer is configured with <code>IsFullScreen="true"</code>, causing it to cover the entire viewport, regardless of its <code>Position</code> parameter. The drawer will slide in from the top as specified by <code>Position="DrawerPosition.Top"</code>.
</p>
<button class="btn btn-primary" @onclick="() => isDrawerFullscreenOpen = true">Open Fullscreen Drawer</button>
<P11DrawerNative @bind-IsOpen="isDrawerFullscreenOpen"
Position="DrawerPosition.Top"
IsFullScreen="true"
Title="Fullscreen Drawer"
ShowCloseButton="false"
AdditionalAttributes="@(new Dictionary<string, object> { { "id", "drawer-fullscreen" } })">
<div style="padding: 20px;">
<p>This drawer is in fullscreen mode. Note how it covers the entire screen, even though its <code>Position</code> is set to `Top`.</p>
<button class="btn btn-secondary" @onclick="() => isDrawerFullscreenOpen = false">Close</button>
</div>
</P11DrawerNative>
<p>Current Status (Fullscreen Demo): @(isDrawerFullscreenOpen ? "Open" : "Closed")</p>@code {
private bool isDrawerAccessibilityWarningOpen = false;
private bool isDrawerFullscreenOpen = false;
}Component API
| Parameter | Type | Default | Description |
|---|---|---|---|
ChildContent |
RenderFragment? |
null |
Gets or sets the content to be rendered inside the drawer. |
IsOpen |
bool |
false |
Gets or sets a boolean indicating whether the drawer is currently open and visible. Use @bind-IsOpen for two-way data binding. |
Position |
DrawerPosition |
DrawerPosition.Left |
Gets or sets the position from which the drawer slides into view. Defaults to DrawerPosition.Left. |
IsFullScreen |
bool |
false |
Gets or sets a boolean indicating whether the drawer should take up the full screen. If true, this overrides the default width/height set by the Position parameter. |
HasOverlay |
bool |
true |
Gets or sets a boolean indicating whether a semi-transparent overlay (backdrop) should be displayed when the drawer is open, to visually block the background content. |
Title |
string? |
null |
Gets or sets the title text for the drawer. If provided, this will be rendered as an <h5> element inside the drawer and will automatically set the aria-labelledby attribute for accessibility. |
AriaLabel |
string? |
null |
Gets or sets the value for the aria-label attribute on the drawer's main element. This provides an accessible name for screen readers when no Title or AriaLabelledby is provided. |
AriaLabelledby |
string? |
null |
Gets or sets the value for the aria-labelledby attribute on the drawer's main element. This should be the ID of an element that labels the drawer. If Title is provided, this parameter is overridden. |
PreventScroll |
bool |
true |
Gets or sets a boolean indicating whether to prevent scrolling of the background content (body element) when the drawer is open. Requires JavaScript interop. |
EnableFocusTrap |
bool |
true |
Gets or sets a boolean indicating whether focus should be trapped inside the drawer when it is open, preventing tabbing to elements outside the drawer. Requires JavaScript interop. |
CloseOnOutsideClick |
bool |
true |
Gets or sets a boolean indicating whether the drawer should close when a click occurs outside the drawer itself (but not on the overlay if HasOverlay is false). Requires JavaScript interop. |
ShowCloseButton |
bool |
false |
Gets or sets a boolean indicating whether a close button (X icon) should be displayed in the top-right corner of the drawer. |
CustomClass |
string? |
null |
Gets or sets an additional CSS class to be applied to the main drawer container. |
CustomSize |
int |
0 |
Sets the width of the drawer. |
ShowDevelopmentErrors |
bool |
true |
Gets or sets a value indicating whether development-time configuration errors should be displayed. Defaults to true. Set to false for production environments. |
AdditionalAttributes |
Dictionary<string, object>? |
null |
Captures additional HTML attributes passed to the component that are not explicitly defined as parameters. These attributes will be applied to the main drawer container element. |
| Events | |||
IsOpenChanged |
EventCallback<bool> |
- | Event callback that is invoked when the IsOpen property changes. Required for @bind-IsOpen functionality. |
OnOverlayClick |
EventCallback |
- | Event callback that is invoked when the overlay (backdrop) is clicked. This typically triggers the closing of the drawer. |