Mobile Sheet Patterns
On mobile, a side sheet looks wrong — it crowds the viewport and forces horizontal eye
movement. The native pattern is the bottom sheet: a panel that slides up from the bottom
edge and dismisses with a downward swipe. Lumeo's Sheet
and Drawer components
support bottom-edge presentation, opt-in swipe-to-close, and the
MobileFullscreen
option for service-driven overlays.
When bottom, when side
| Side | Use for |
|---|---|
| Bottom | Action sheets, filter panels, quick pickers, anything triggered by a thumb-reachable button. Default for mobile. |
| Right / Left | Desktop and tablet. On phones, only for full-height navigation drawers triggered by a hamburger. |
| Top | Rare — notification trays, search overlays. Avoid for forms (keyboard pushes the sheet off-screen). |
Responsive side switching
One overlay, two presentations. Inject IResponsiveService
and pick the side from IsMobile
so the same component renders as a right-side sheet on desktop and a bottom sheet on phone.
Subscribe to ViewportChanged
so a tablet rotation flips the layout without re-opening the sheet.
@inject IResponsiveService Viewport
@implements IDisposable
<Sheet @bind-Open="_open">
<SheetContent Side="@(Viewport.IsMobile ? Lumeo.Side.Bottom : Lumeo.Side.Right)" Size="SheetContent.SheetSize.Default">
<SheetHeader><SheetTitle>Filters</SheetTitle></SheetHeader>
<div class="flex-1 overflow-y-auto p-6">
@* filter UI *@
</div>
</SheetContent>
</Sheet>
@code {
private bool _open;
protected override async Task OnAfterRenderAsync(bool firstRender)
{
if (!firstRender) return;
await Viewport.EnsureInitialisedAsync();
Viewport.ViewportChanged += OnViewportChanged;
StateHasChanged();
}
private void OnViewportChanged(ViewportInfo _) => InvokeAsync(StateHasChanged);
public void Dispose() => Viewport.ViewportChanged -= OnViewportChanged;
}Mobile-fullscreen for service overlays
When you open a Dialog, Sheet, or Drawer through
OverlayService, set
OverlayOptions.MobileFullscreen = true
to force the overlay to fill the viewport below the
MobileBreakpoint (default
768px). The size / side parameters still apply on tablet and desktop — this is a phone-only
override.
@inject IOverlayService Overlays
<Button OnClick="OpenFilters">Filters</Button>
@code {
private Task OpenFilters() =>
Overlays.ShowSheetAsync<FilterPanel>(
title: "Filters",
side: Lumeo.Side.Right,
size: SheetSize.Default,
options: new OverlayOptions { MobileFullscreen = true });
}Swipe-to-close (opt-in)
Swipe-to-dismiss is off by default because it conflicts with scrollable
content. Opt in with SwipeToClose="true"
on SheetContent for
sheets whose content fits the viewport without internal scrolling (filter panels, picker
menus, action sheets).
<Sheet @bind-Open="_open">
<SheetContent Side="Lumeo.Side.Bottom" SwipeToClose="true">
<SheetHeader><SheetTitle>Sort by</SheetTitle></SheetHeader>
@* compact list — fits without scrolling, so swipe is safe *@
</SheetContent>
</Sheet>
<!-- form sheet: keep swipe OFF (default) so a scroll gesture doesn't dismiss it -->
<Sheet @bind-Open="_formOpen">
<SheetContent Side="Lumeo.Side.Bottom" PreventClose="true">
@* user must use the explicit Cancel or Save buttons *@
</SheetContent>
</Sheet>Safe areas and the keyboard
Bottom sheets must respect the home indicator on iOS and the navigation pill on Android. Wrap
the footer in SafeArea
with Bottom="true" so
the primary action stays tappable. When the soft keyboard appears, the sheet's
flex layout keeps the
footer above the keyboard — but only if the body uses
flex-1 overflow-y-auto.
<Sheet @bind-Open="_open">
<SheetContent Side="Lumeo.Side.Bottom">
<div class="flex flex-col flex-1 min-h-0">
<SheetHeader><SheetTitle>New message</SheetTitle></SheetHeader>
<div class="flex-1 overflow-y-auto px-4 py-3">
<Textarea @bind-Value="_body" Rows="8" />
</div>
<SafeArea Bottom="true">
<SheetFooter>
<Button Variant="Button.ButtonVariant.Outline"
OnClick="() => _open = false">Cancel</Button>
<Button OnClick="SendAsync">Send</Button>
</SheetFooter>
</SafeArea>
</div>
</SheetContent>
</Sheet>See also
- Sheet
- Drawer — non-modal mobile drawer
- Safe Area
- Swipe Actions