# Overlay Service

Source: https://lumeo.nativ.sh/docs/services/overlay

# Overlay Service

Open dialogs, sheets, drawers, and alert dialogs programmatically from C# code and await their results.

## Quick Start

The `OverlayService` lets you open overlays imperatively instead of declaring them in markup. Every method returns a `Task<OverlayResult>` so you can `await` the user's response and read back data they entered.

`OverlayProvider` is already included in the default Lumeo layout. If you are using a custom layout, make sure to add it as shown in step 1.

### Step 1 — Add the provider to your layout

Place `<OverlayProvider />` once in your root layout. It renders all active overlays.

<!-- MainLayout.razor --> <div class="min-h-screen"> @Body <OverlayProvider /> </div>

### Step 2 — Create a content component

Your content component receives an `OverlayReference` via `[CascadingParameter]`. Call `Overlay.Close(data)` to return a result, or `Overlay.Cancel()` to dismiss without returning data.

<!-- EditProfileForm.razor --> <Stack Gap="4"> <Stack Gap="2"> <Label>Name</Label> <Input @bind-Value="\_name" Placeholder="Enter your name..." /> </Stack> <Stack Gap="2"> <Label>Email</Label> <Input @bind-Value="\_email" Placeholder="Enter your email..." /> </Stack> <Flex Justify="end" Gap="2" Class="pt-2"> <Button Variant="Button.ButtonVariant.Outline" OnClick="() => Overlay.Cancel()">Cancel</Button> <Button OnClick="Submit">Save</Button> </Flex> </Stack> @code { \[CascadingParameter\] public OverlayReference Overlay { get; set; } = default!; private string \_name = ""; private string \_email = ""; private void Submit() { Overlay.Close(new { Name = \_name, Email = \_email }); } }

### Step 3 — Open from code

Inject `OverlayService` and call one of its `Show*Async` methods. The call awaits until the user closes or cancels the overlay.

@inject OverlayService OverlayService @using Lumeo.Services @code { private async Task EditProfile() { var result = await OverlayService.ShowDialogAsync<EditProfileForm>("Edit Profile"); if (!result.Cancelled) { var data = result.GetData<dynamic>(); Console.WriteLine($"Name: {data?.Name}, Email: {data?.Email}"); } } }

## Dialog

Opens a centered modal dialog with your component as the body content. The dialog includes a title bar and close button by default.

Live Demo

Open Dialog Open Wide Dialog (max-w-2xl)

// Basic dialog var result = await OverlayService.ShowDialogAsync<OverlayDemoContent>("Edit Profile"); if (!result.Cancelled) { // The user submitted — result.Data contains the object passed to Close() var data = result.GetData<dynamic>(); } // Dialog with custom width var result = await OverlayService.ShowDialogAsync<OverlayDemoContent>( title: "Edit Profile", options: new OverlayOptions { Class = "max-w-2xl" } );

## Sheet

Opens a panel that slides in from any edge of the screen. Use sheets for secondary navigation, settings panels, detail views, or any content that should overlay from a specific direction.

Slide from any side

Right Left Top Bottom

// Sheet from the right (default side) var result = await OverlayService.ShowSheetAsync<OverlayDemoContent>( title: "Settings", side: Lumeo.Side.Right, size: SheetSize.Default ); // Sheet from the left, large size var result = await OverlayService.ShowSheetAsync<OverlayDemoContent>( title: "Navigation", side: Lumeo.Side.Left, size: SheetSize.Lg ); // Full-width sheet from the bottom var result = await OverlayService.ShowSheetAsync<OverlayDemoContent>( title: "Details", side: Lumeo.Side.Bottom, size: SheetSize.Full );

Sheet sizes

The `SheetSize` enum controls the width (for left/right) or height (for top/bottom) of the sheet panel.

Size

Description

Sm

Small — narrow panel for simple content

Default

Standard width — good for forms and settings

Lg

Large — for detail views and complex content

Xl

Extra large — for data tables or wide layouts

Full

Full width/height — covers the entire edge

## Drawer

Opens a bottom drawer, ideal for mobile-friendly interactions. Drawers slide up from the bottom of the viewport and are commonly used for action menus, date pickers, or compact forms.

Live Demo

Open Drawer

var result = await OverlayService.ShowDrawerAsync<OverlayDemoContent>("Edit Profile"); if (!result.Cancelled) { var data = result.GetData<dynamic>(); Console.WriteLine($"Name: {data?.Name}"); }

## Alert Dialog

A simple confirm/cancel dialog that requires no custom component. Pass an `AlertDialogOptions` object to configure the title, description, button text, and whether the action is destructive.

Confirm action (non-destructive)

Standard confirmation before saving or performing a significant action.

Save Changes

var result = await OverlayService.ShowAlertDialogAsync(new AlertDialogOptions { Title = "Save changes?", Description = "This will overwrite your existing data.", ConfirmText = "Save", CancelText = "Cancel" }); if (!result.Cancelled) { await SaveAsync(); }

Destructive action (red confirm button)

Use `IsDestructive = true` to render the confirm button with destructive styling, signaling an irreversible action.

Delete Account

var result = await OverlayService.ShowAlertDialogAsync(new AlertDialogOptions { Title = "Delete your account?", Description = "This action cannot be undone. All of your data will be permanently removed.", ConfirmText = "Delete Account", CancelText = "Keep Account", IsDestructive = true }); if (!result.Cancelled) { await DeleteAccountAsync(); }

## Passing Parameters

Use `OverlayParameters` to pass data into your content component. The fluent `.Add()` API chains cleanly and parameters are fed to Blazor's `DynamicComponent`, so they map directly to `[Parameter]` properties on your component.

### Building parameters (caller side)

var parameters = new OverlayParameters() .Add("UserId", 42) .Add("Mode", "edit") .Add("ReadOnly", false); var result = await OverlayService.ShowDialogAsync<EditUserForm>( "Edit User", parameters: parameters );

### Receiving parameters (content component)

Each key in `OverlayParameters` maps to a `[Parameter]` property with the same name. You can also access raw parameters through the `OverlayReference.Parameters` property.

@code { // Option A: Blazor \[Parameter\] binding (recommended) \[Parameter\] public int UserId { get; set; } \[Parameter\] public string Mode { get; set; } = ""; \[Parameter\] public bool ReadOnly { get; set; } // Always available via cascading parameter \[CascadingParameter\] public OverlayReference Overlay { get; set; } = default!; // Option B: Read from OverlayReference.Parameters directly protected override void OnInitialized() { var userId = Overlay.Parameters?.Get<int>("UserId"); } }

## Getting Results

Every `Show*Async` method returns a `Task<OverlayResult>`. The task completes when the user closes or cancels the overlay. Check `result.Cancelled` to determine which action was taken.

### Returning data from Close()

Inside your content component, call `Overlay.Close(data)` to pass any object back to the caller. The data is available on `result.Data` (as `object?`) or via the typed helper `result.GetData<T>()`.

// Inside content component — close with data Overlay.Close(new { Name = \_name, Email = \_email }); // Close without data (just confirms) Overlay.Close(); // Cancel (result.Cancelled will be true) Overlay.Cancel();

### Reading the result (caller side)

var result = await OverlayService.ShowDialogAsync<EditProfileForm>("Edit Profile"); // Check if cancelled if (result.Cancelled) { // User clicked Cancel or dismissed the overlay return; } // Read raw data object? raw = result.Data; // Read typed data — returns default if cast fails var profile = result.GetData<ProfileModel>(); if (profile is not null) { await SaveProfileAsync(profile); }

### Full round-trip example

This shows the complete flow: open an overlay, let the user fill a form, close it, and read the result.

// Page.razor @inject OverlayService OverlayService @using Lumeo.Services <Button OnClick="OpenEditor">Edit User</Button> @if (\_lastSaved is not null) { <Alert>Saved: @\_lastSaved</Alert> } @code { private string? \_lastSaved; private async Task OpenEditor() { var result = await OverlayService.ShowDialogAsync<UserEditorForm>( "Edit User", parameters: new OverlayParameters() .Add("UserId", 42) .Add("CurrentName", "Jane Doe") ); if (result.Cancelled) return; var data = result.GetData<dynamic>(); \_lastSaved = $"Name={data?.Name}, Email={data?.Email}"; } } // UserEditorForm.razor <Stack Gap="4"> <Input @bind-Value="\_name" Placeholder="Name" /> <Input @bind-Value="\_email" Placeholder="Email" /> <Flex Justify="end" Gap="2"> <Button Variant="Button.ButtonVariant.Outline" OnClick="() => Overlay.Cancel()">Cancel</Button> <Button OnClick="Save">Save</Button> </Flex> </Stack> @code { \[CascadingParameter\] public OverlayReference Overlay { get; set; } = default!; \[Parameter\] public int UserId { get; set; } \[Parameter\] public string CurrentName { get; set; } = ""; private string \_name = ""; private string \_email = ""; protected override void OnInitialized() { \_name = CurrentName; } private void Save() => Overlay.Close(new { Name = \_name, Email = \_email }); }

## Options & Customization

All overlay methods accept an optional `OverlayOptions` record to control behavior and appearance.

### PreventClose

Set `PreventClose = true` to prevent the overlay from being dismissed by clicking outside or pressing Escape. The user must explicitly click a button inside your content component to close the overlay.

var result = await OverlayService.ShowDialogAsync<ImportantForm>( "Required Information", options: new OverlayOptions { PreventClose = true } );

Live Demo — PreventClose

Try clicking outside the dialog or pressing Escape. It won't close until you use a button.

Open Non-Dismissible Dialog

### Custom CSS Class

Use the `Class` property to add Tailwind utility classes to the overlay container. This is especially useful for controlling width.

// Make the dialog wider options: new OverlayOptions { Class = "max-w-2xl" } // Extra wide for data-heavy content options: new OverlayOptions { Class = "max-w-4xl" } // Combine options options: new OverlayOptions { Class = "max-w-3xl", PreventClose = true }

### SheetSide and SheetSize

For sheets, `SheetSide` and `SheetSize` are passed as direct parameters to `ShowSheetAsync`. They are also available on `OverlayOptions` for advanced scenarios.

// Side and size are method parameters (recommended) await OverlayService.ShowSheetAsync<MyComponent>( title: "Settings", side: Lumeo.Side.Left, size: SheetSize.Lg ); // Can also be set via options (they will be overridden by method parameters) await OverlayService.ShowSheetAsync<MyComponent>( title: "Settings", side: Lumeo.Side.Right, size: SheetSize.Xl, options: new OverlayOptions { PreventClose = true } );

## Content Component Pattern

Every component rendered inside an overlay receives an `OverlayReference` as a `[CascadingParameter]`. This is the component's handle to control the overlay it lives in.

Complete content component example

<!-- CreateUserForm.razor --> @namespace MyApp.Components @using Lumeo.Services <Stack Gap="4" Class="py-2"> <Stack Gap="2"> <Label>Full Name</Label> <Input @bind-Value="\_name" Placeholder="Enter name..." /> </Stack> <Stack Gap="2"> <Label>Email</Label> <Input @bind-Value="\_email" Placeholder="user@example.com" /> </Stack> <Stack Gap="2"> <Label>Role</Label> <Select @bind-Value="\_role"> <SelectTrigger> <SelectValue Placeholder="Select a role" /> </SelectTrigger> <SelectContent> <SelectItem Value="@("admin")">Admin</SelectItem> <SelectItem Value="@("editor")">Editor</SelectItem> <SelectItem Value="@("viewer")">Viewer</SelectItem> </SelectContent> </Select> </Stack> <Flex Justify="end" Gap="2" Class="pt-4"> <Button Variant="Button.ButtonVariant.Outline" OnClick="HandleCancel">Cancel</Button> <Button OnClick="HandleSubmit" disabled="@(!IsValid)">Create User</Button> </Flex> </Stack> @code { // Cascading parameter — always available in overlay content \[CascadingParameter\] public OverlayReference Overlay { get; set; } = default!; // Parameters passed via OverlayParameters.Add() \[Parameter\] public string DefaultRole { get; set; } = "viewer"; \[Parameter\] public int TeamId { get; set; } private string \_name = ""; private string \_email = ""; private string \_role = ""; private bool IsValid => !string.IsNullOrWhiteSpace(\_name) && !string.IsNullOrWhiteSpace(\_email); protected override void OnInitialized() { \_role = DefaultRole; } private void HandleSubmit() { // Close with data — caller receives this in OverlayResult.Data Overlay.Close(new { Name = \_name, Email = \_email, Role = \_role, TeamId }); } private void HandleCancel() { // Cancel — caller sees OverlayResult.Cancelled = true Overlay.Cancel(); } }

Tip: You can also read parameters dynamically via `Overlay.Parameters?.Get<int>("TeamId")` if you prefer not to declare `[Parameter]` properties.

## API Reference

### OverlayService Methods

6 methods

Method

Returns

Description

ShowDialogAsync<T>(title?, parameters?, options?)

Task<OverlayResult>

Opens a centered modal dialog with component `T` as the body.

ShowSheetAsync<T>(title?, side, size, parameters?, options?)

Task<OverlayResult>

Opens a slide-in panel from the specified edge with component `T`.

ShowDrawerAsync<T>(title?, parameters?, options?)

Task<OverlayResult>

Opens a bottom drawer with component `T`.

ShowAlertDialogAsync(AlertDialogOptions)

Task<OverlayResult>

Shows a built-in confirm/cancel alert dialog. No custom component needed.

Close(overlayId, result?)

void

Closes a specific overlay by ID and returns data. Typically called internally via `OverlayReference.Close()`.

Cancel(overlayId)

void

Cancels a specific overlay by ID. Typically called internally via `OverlayReference.Cancel()`.

### OverlayResult

Returned by all `Show*Async` methods when the overlay closes.

Member

Type

Description

Cancelled

bool

`true` when the user dismissed the overlay without confirming (clicked Cancel, backdrop, or pressed Escape).

Data

object?

The raw value passed to `Overlay.Close(data)`. Null when cancelled or closed without data.

GetData<T>()

T?

Attempts to cast `Data` to type `T`. Returns `default` if the cast fails.

Static factory methods: `OverlayResult.Ok(data?)` and `OverlayResult.CancelResult()`.

### OverlayReference

Cascaded into every content component. This is how your component communicates with the overlay it lives in.

Member

Type

Description

Id

string

Unique identifier for this overlay instance.

Parameters

OverlayParameters?

The parameters passed when the overlay was opened. Use `.Get<T>(name)` to read values.

Close(result?)

void

Close the overlay and return data to the caller. Pass any object as the result.

Cancel()

void

Dismiss the overlay without returning data. Sets `Cancelled = true` on the result.

### OverlayParameters

Fluent builder for passing named values to content components.

Method

Returns

Description

Add(string name, object value)

OverlayParameters

Adds a named parameter. Returns `this` for chaining.

Get<T>(string name)

T?

Retrieves a parameter by name, cast to `T`. Returns `default` if not found or wrong type.

ToDictionary()

Dictionary<string, object>

Converts all parameters to a dictionary. Used internally by the overlay provider.

### OverlayOptions

Record type that controls overlay appearance and behavior.

Property

Type

Default

Description

Class

string?

null

Additional CSS classes applied to the overlay container (e.g., `max-w-2xl`).

PreventClose

bool

false

When `true`, prevents dismissal via backdrop click or Escape key.

SheetSide

SheetSide

Right

Which edge the sheet slides in from. Set automatically by `ShowSheetAsync`.

SheetSize

SheetSize

Default

Width (left/right) or height (top/bottom) of the sheet. Set automatically by `ShowSheetAsync`.

### AlertDialogOptions

Record type that configures the built-in alert dialog.

Property

Type

Default

Description

Title

string

"Are you sure?"

The heading text displayed at the top of the alert dialog.

Description

string?

null

Optional body text explaining the action or its consequences.

ConfirmText

string

"Continue"

Label for the confirm/action button.

CancelText

string

"Cancel"

Label for the cancel/dismiss button.

IsDestructive

bool

false

When `true`, the confirm button renders with destructive styling (red).

### SheetSide Enum

Value

Description

Top

Slides down from the top of the viewport.

Right

Slides in from the right edge. Default value.

Bottom

Slides up from the bottom of the viewport.

Left

Slides in from the left edge.

### SheetSize Enum

Value

Description

Sm

Small — compact panel for simple content.

Default

Standard size — suitable for most forms and settings panels.

Lg

Large — for detail views and complex content.

Xl

Extra large — for data tables or wide layouts.

Full

Full width or height — covers the entire edge of the viewport.
