Show native BottomSheets with .NET MAUI!
- Built-in NavigationService
- Open any ContenPage or View as BottomSheet
- Create BottomSheets in any layout
- Configurable header
- MVVM support
Check out sample project to see the API in action!.
MacCatalyst
implementation details
Install package Plugin.Maui.BottomSheet
Enable this plugin by calling UseBottomSheet()
in your MauiProgram.cs
var builder = MauiApp.CreateBuilder();
builder
.UseMauiApp<App>()
.UseMauiBottomSheet()
.ConfigureFonts(fonts =>
{
fonts.AddFont("OpenSans-Regular.ttf", "OpenSansRegular");
fonts.AddFont("OpenSans-Semibold.ttf", "OpenSansSemibold");
})
.RegisterPages()
.RegisterViewModels()
.PlatformServices();
#if DEBUG
builder.Logging.AddDebug();
#endif
return builder.Build();
Type | Name | Description |
---|---|---|
bool | IsModal | Is interaction with content under BottomSheet enabled |
bool | IsCancelable | Can be closed by user either through gestures or clicking in background |
bool | HasHandle | Show handle |
bool | ShowHeader | Show header |
bool | IsOpen | Open or close |
bool | IsDraggable | Can be dragged(Useful if drawing gestures are made inside bottom sheet) |
List<BottomSheetState> | States | Allowed states. CurrentState must be a value of this collection. |
BottomSheetState | CurrentState | Current state |
BottomSheetHeader | Header | Configure header |
BottomSheetPeek | Peek | Configure peek(requieres at least iOS 16 -- all other platforms are supported) |
BottomSheetContent | Content | Configure content |
double | Padding | Padding |
Colors | BackgroundColor | Background color |
bool | IgnoreSafeArea | Ignore safe area(currently only implemented in iOS) |
float | CornerRadius | Top left and top right corner radius |
Color | WindowBackgroundColor | Window background color. If BottomSheet is non-modal no window color is applied |
Name | Description |
---|---|
Peek | Fractional height |
Medium | Half screen height |
Large | Full screen height |
Type | Name | Description |
---|---|---|
string | TitleText | Title text |
Button | TopLeftButton | Top left button |
Button | TopRightButton | Top right button |
DataTemplate | HeaderDataTemplate | Custom view. If set HeaderAppearance, TitleText and TopLeft-and Right buttons are ignored. |
BottomSheetHeaderButtonAppearanceMode | HeaderAppearance | Set which buttons should be displayed. |
bool | ShowCloseButton | Built in button to close the BottomSheet. Build in Button will replace top right or top left button. |
CloseButtonPosition | CloseButtonPosition | Show button on the left or right |
Name | Description |
---|---|
None | Don't show a button |
LeftAndRightButton | Show a button on the left and right |
LeftButton | Show a button on the left |
RightButton | Show a button on the right |
Name | Description |
---|---|
Left | Show button on the left |
Right | Show button on the right |
Type | Name | Description |
---|---|---|
double | PeekHeight | Fixed peek detent height |
DataTemplate | PeekViewDataTemplate | Peek view. Height will be calculated automatically if PeekHeight is NaN. |
Type | Name | Description |
---|---|---|
DataTemplate | ContentTemplate | Content view. |
TopRightButtonCommand
TopRightButtonCommandParameter
TopLeftButtonCommand
TopLeftButtonCommandParameter
ClosingCommand
ClosingCommandParameter
ClosedCommand
ClosedCommandParameter
OpeningCommand
OpeningCommandParameter
OpenedCommand
OpenedCommandParameter
Closing
Closed
Opening
Opened
Apple decided that sheets are always modal.
By default a theme based on ThemeOverlay.MaterialComponents.BottomSheetDialog
is used to theme BottomSheets
.
To enable EdgeToEdge by default the derived theme sets the navigationBarColor
to transparent.
You can create you own themes and apply them to different BottomSheets
To set a custom theme call the platform specific extension method before the sheet is opened.
MyBottomSheet.On<Android>().SetTheme(Resource.Style.My_Awesome_BottomSheetDialog);
Theme changes are not possible if the sheet is open and will be applied after it's closed and opened again.
EdgeToEdge support is built-in and enabled by default. If you create your own theme make sure to derive from ThemeOverlay.MaterialComponents.BottomSheetDialog
and that navigationBarColor
is translucent.
Otherwise EdgeToEdge is disabled for that sheet.
In order to make use of sheet within XAML you can use this namespace: xmlns:bottomsheet="http://pluginmauibottomsheet.com"
BottomSheet
is a View
and can be added in any layout or control which accepts View
.
To open/close a BottomSheet simply set IsOpen
property to true/false. You can have multiple BottomSheets on one page.
<bottomsheet:BottomSheet
Padding="20"
IsOpen="{Binding IsOpen}"
States="Peek,Medium,Large"
HasHandle="{Binding HasHandle}"
IsCancelable="{Binding IsCancelable}"
ShowHeader="{Binding ShowHeader}"
IsDraggable="{Binding IsDraggable}">
<bottomsheet:BottomSheet.Header>
<bottomsheet:BottomSheetHeader
TitleText="{Binding Title}"
HeaderAppearance="{Binding HeaderButtonAppearanceMode}">
<bottomsheet:BottomSheetHeader.TopLeftButton>
<Button Text="Top left" Command="{Binding TopLefButtonCommand}"></Button>
</bottomsheet:BottomSheetHeader.TopLeftButton>
<bottomsheet:BottomSheetHeader.TopRightButton>
<Button Text="Top right" Command="{Binding TopRightButtonCommand}"></Button>
</bottomsheet:BottomSheetHeader.TopRightButton>
</bottomsheet:BottomSheetHeader>
</bottomsheet:BottomSheet.Header>
<bottomsheet:BottomSheet.Peek>
<bottomsheet:BottomSheetPeek>
<bottomsheet:BottomSheetPeek.PeekViewDataTemplate>
<DataTemplate x:DataType="local:ShowCaseViewModel">
<Grid Margin="0,10,0,10"
ColumnSpacing="10"
RowSpacing="10"
RowDefinitions="40,40,40"
ColumnDefinitions="*,*">
<Label VerticalTextAlignment="Center" Grid.Row="0" Text="Title"/>
<Entry Grid.Row="0" Grid.Column="1" Text="{Binding Title}"/>
<Button Grid.Row="1" Text="None" Command="{Binding HeaderButtonAppearanceModeNoneCommand}"></Button>
<Button Grid.Row="1" Grid.Column="1" Text="Left" Command="{Binding HeaderButtonAppearanceModeLeftCommand}"></Button>
<Button Grid.Row="2" Text="Right" Command="{Binding HeaderButtonAppearanceModeRightCommand}"></Button>
<Button Grid.Row="2" Grid.Column="1" Text="LeftAndRight" Command="{Binding HeaderButtonAppearanceModeLeftAndRightCommand}"></Button>
</Grid>
</DataTemplate>
</bottomsheet:BottomSheetPeek.PeekViewDataTemplate>
</bottomsheet:BottomSheetPeek>
</bottomsheet:BottomSheet.Peek>
<bottomsheet:BottomSheet.Content>
<bottomsheet:BottomSheetContent>
<bottomsheet:BottomSheetContent.ContentTemplate>
<DataTemplate x:DataType="local:ShowCaseViewModel">
<Grid RowDefinitions="40,40,40,40" RowSpacing="10" ColumnDefinitions="*, 50">
<Label Text="Has handle?"></Label>
<Label Grid.Row="1" Text="Is cancelable?"></Label>
<Label Grid.Row="2" Text="Show header?"></Label>
<Label Grid.Row="3" Text="Is draggable?"></Label>
<Switch Grid.Column="1" IsToggled="{Binding HasHandle}"></Switch>
<Switch Grid.Row="1" Grid.Column="1" IsToggled="{Binding IsCancelable}"></Switch>
<Switch Grid.Row="2" Grid.Column="1" IsToggled="{Binding ShowHeader}"></Switch>
<Switch Grid.Row="3" Grid.Column="1" IsToggled="{Binding IsDraggable}"></Switch>
</Grid>
</DataTemplate>
</bottomsheet:BottomSheetContent.ContentTemplate>
</bottomsheet:BottomSheetContent>
</bottomsheet:BottomSheet.Content>
</bottomsheet:BottomSheet>
IBottomSheetNavigationService
is be registered automatically and can be resolved.
private readonly IBottomSheetNavigationService _bottomSheetNavigationService;
public MainViewModel(IBottomSheetNavigationService bottomSheetNavigationService)
{
_bottomSheetNavigationService = bottomSheetNavigationService;
}
You have to register your View as BottomSheet to enable navigation.
If the BindingContext
of View
is assigned during initialization it will be assigned to the BottomSheet
. Reference
builder.Services.AddBottomSheet<ShowCasePage>("Showcase");
This will add a named "Showcase" BottomSheet
to the container
To open it simply call _bottomSheetNavigationService.NavigateTo("Showcase");
You can map your BottomSheet
to a ViewModel
to simplify navigation.
builder.Services.AddBottomSheet<SomeBottomSheet, SomeViewModel>("SomeBottomSheet");
This adds a named BottomSheet
SomeBottomSheet which will be wired to SomeViewModel
during navigation.
To navigate to SomeBottomSheet just execute _bottomSheetNavigationService.NavigateTo("SomeBottomSheet");
The BindingContext
of SomeBottomSheet
will be SomeViewModel
.
You can also add a default BottomSheet
navigation configuration
.UseBottomSheet(config => config.CopyPagePropertiesToBottomSheet = true);
will copy all applicable properties from registered Pages
to the BottomSheet
builder.Services.AddBottomSheet<ShowCasePage>("Showcase",
(sheet, page) =>
{
sheet.States = [BottomSheetState.Medium, BottomSheetState.Large];
sheet.CurrentState = BottomSheetState.Large;
sheet.ShowHeader = true;
sheet.Header = new BottomSheetHeader()
{
TitleText = page.Title,
};
});
To override the default configuration
_bottomSheetNavigationService.NavigateTo("Showcase", configure: (sheet) =>
{
sheet.Header.TitleText = "My new title";
});
You can pass parameters on each navigation(this follows principle of shell navigation)
Pass an instance of BottomSheetNavigationParameters
to navigation and if target ViewModel
implements IQueryAttributable
parameters will be applied.
_bottomSheetNavigationService.NavigateTo("Showcase", new BottomSheetNavigationParameters()
{
["SomeKey"] = "SomeValue",
});
To manually set the ViewModel
it has to be available in the container
builder.Services.AddTransient<SomeViewModel>();
_bottomSheetNavigationService.NavigateTo<SomeViewModel>("Showcase");
To close a BottomSheet
simply call GoBack
or ClearBottomSheetStack
(if you have multiple sheets open and want to close all of them)