Skip to main content
twblazor
Home
  • Get started
  • Tailwind with Blazor
  • Why twblazor?
  • Theme
  • Class Merge
    • Configuring localization
    • RTL Provider
  • Breadcrumb
  • Card
  • Carousel
  • Collapse
  • DrawerNew
  • Footer
  • MenuNew
  • Navbar
  • On This PageNew
  • Sidebar
  • Stepper
  • Tabs
  • Tree List
  • Button
  • FormNew
    • AutocompleteNew
    • Checkbox
    • Color Picker
    • Date Picker
    • Date Range Picker
    • Datetime Picker
    • Datetime Range Picker
    • File Upload
    • NumericNew
    • Radio Button
    • RatingNew
    • Select
    • Slider
    • Switch
    • Textfield
    • Time Picker
    • Time Range Picker
  • Alert
  • Avatar
  • Chip
  • Icon
  • PopoverNew
  • Progress
  • Skeleton
  • Spinner
  • Tooltip
  • Data Table
  • Pagination
  • Pick List
  • BarcodeNew
  • QR CodeNew
  • CalendarNew
  • Table
  • AttachmentNew
  • Overview
    • Bar
    • Bullet
    • Column
    • Dot Plot
    • Dumbbell
    • Icon
    • Lollipop
    • Radial Bar
    • Range
    • Word Cloud
    • Area
    • Bump
    • Bump Area
    • Candlestick
    • Gantt
    • Horizon
    • Line
    • Slope
    • Small Multiples
    • Stream Graph
    • Funnel
    • Gauge
    • Marimekko
    • Nightingale
    • Pie
    • Treemap
    • Waffle
    • Waterfall
    • Circular Treemap
    • Convex Treemap
    • Dendrogram
    • Sunburst
    • Barcode
    • Beeswarm
    • Box Plot
    • Density Plot
    • Histogram
    • Radial Histogram
    • Ridgeline
    • Strip Plot
    • Violin Plot
    • Categorical Scatter
    • Contour
    • Hexagonal Binning
    • Quadrant
    • Scatter
    • Heatmap
    • Matrix
    • Parallel Coordinates
    • Radar
    • Arc Diagram
    • Chord Diagram
    • Flowchart
    • Network Diagram
    • Sankey
    • Euler Diagram
    • Venn Diagram
  • Bubble
  • Marker
  • Message
  • Dialog Service
  • Toast Service
API DocumentationAI Agents & Skills
Home Get Started

Layout

TwDrawer

TwDrawer is a Blazor drawer component: a panel that slides in from any edge of the screen, as a side sheet or a bottom sheet, with focus management built in.

Last updated 23 October 2026

Please be aware this component is new, may have bugs and/or be subject to change. Please report any bugs at https://github.com/twblazor/twblazor/issues.

Basic usage

Bind Open with @bind-Open and open it from a button. Give it a Title, which also names it for screen readers, and an optional Description. Put the actions in FooterContent: the footer stays in view while the body scrolls. The drawer slides in from the end edge, moves focus to its first field, and closes on Escape, on the close button, or on a click on the backdrop.
RAZOR
<TwButton Label="Edit profile" StartIcon="Icon.Pencil" OnClick="@(() => profileOpen = true)" />

<TwDrawer @bind-Open="profileOpen" Title="Edit profile" Description="Changes are saved to your public profile.">
    <ChildContent>
        <div class="flex flex-col gap-4">
            <TwTextfield T="string" Label="Name" @bind-Value="profileName" />
            <TwTextfield T="string" Label="Username" @bind-Value="profileUsername" />
            <TwTextfield T="string" Label="Website" InputType="url" @bind-Value="profileWebsite" />
        </div>
    </ChildContent>
    <FooterContent>
        <TwButton Label="Cancel" Variant="ButtonVariant.Outlined" OnClick="@(() => profileOpen = false)" />
        <TwButton Label="Save changes" OnClick="@(() => profileOpen = false)" />
    </FooterContent>
</TwDrawer>
CSHARP
@code {
    private bool profileOpen;
    private string profileName = "John Doe";
    private string profileUsername = "john";
    private string profileWebsite = "https://twblazor.com";
}

Position

Set Position to slide the drawer in from another edge. Start and End follow the reading direction, so they swap sides in a right to left layout. Bottom makes a bottom sheet, which suits a phone, where it sits near the thumb.
RAZOR
<div class="flex flex-wrap gap-3">
    <TwButton Label="Start" Variant="ButtonVariant.Outlined" OnClick="@(() => startOpen = true)" />
    <TwButton Label="End" Variant="ButtonVariant.Outlined" OnClick="@(() => endOpen = true)" />
    <TwButton Label="Top" Variant="ButtonVariant.Outlined" OnClick="@(() => topOpen = true)" />
    <TwButton Label="Bottom" Variant="ButtonVariant.Outlined" OnClick="@(() => bottomOpen = true)" />
</div>

<TwDrawer @bind-Open="startOpen" Position="DrawerPosition.Start" Title="Start drawer">
    <p>Slides in from the start edge: the left in a left to right layout.</p>
</TwDrawer>
<TwDrawer @bind-Open="endOpen" Position="DrawerPosition.End" Title="End drawer">
    <p>Slides in from the end edge: the right in a left to right layout.</p>
</TwDrawer>
<TwDrawer @bind-Open="topOpen" Position="DrawerPosition.Top" Title="Top drawer">
    <p>Slides down from the top edge, for a search or an announcement.</p>
</TwDrawer>
<TwDrawer @bind-Open="bottomOpen" Position="DrawerPosition.Bottom" Title="Bottom sheet">
    <p>Slides up from the bottom edge and keeps clear of the home indicator on a phone.</p>
</TwDrawer>
CSHARP
@code {
    private bool startOpen;
    private bool endOpen;
    private bool topOpen;
    private bool bottomOpen;
}

Size

Set Size to Small, Medium (the default), Large or Full. On the start and end edges it sets the width, on the top and bottom edges the most height the drawer takes before its body scrolls. Below Full, a side drawer leaves a strip of the page showing on a phone, so the backdrop can still be tapped to close it.
RAZOR
<div class="flex flex-wrap gap-3">
    @foreach (var size in Enum.GetValues<DrawerSize>())
    {
        <TwButton Label="@size.ToString()" Variant="ButtonVariant.Outlined" OnClick="@(() => OpenSized(size))" />
    }
</div>

<TwDrawer @bind-Open="sizedOpen" Size="sizedSize" Title="@($"{sizedSize} drawer")">
    <p>This drawer uses <code>Size="DrawerSize.@sizedSize"</code>.</p>
</TwDrawer>
CSHARP
@code {
    private bool sizedOpen;
    private DrawerSize sizedSize = DrawerSize.Medium;
    
    private void OpenSized(DrawerSize size)
    {
        sizedSize = size;
        sizedOpen = true;
    }
}

Action sheet

A bottom sheet with a list of actions is a familiar pattern on a phone. Make each action a button tall enough to tap, with its icon beside a text label. The drawer has no title here, so it is named with AriaLabel, and ShowCloseButton="false" drops the close button because the sheet has a Cancel action of its own.

RAZOR
<TwButton Label="Share" StartIcon="Icon.Share" Variant="ButtonVariant.Outlined" OnClick="@(() => sheetOpen = true)" />

<TwDrawer @bind-Open="sheetOpen" Position="DrawerPosition.Bottom" Size="DrawerSize.Small" AriaLabel="Share document" ShowCloseButton="false" ContentClass="px-2 py-2">
    <ul class="flex flex-col">
        @foreach (var action in sheetActions)
        {
            <li>
                <button type="button" class="flex w-full min-h-12 items-center gap-3 rounded-lg px-3 text-start hover:bg-black/5 dark:hover:bg-white/10 focus-visible:outline-2 focus-visible:outline-purple-600 cursor-pointer" @onclick="@(() => RunAction(action.Label))">
                    <TwIcon Icon="action.Icon" />
                    <span>@action.Label</span>
                </button>
            </li>
        }
        <li class="mt-1 border-t border-black/10 pt-1 dark:border-white/15">
            <button type="button" class="flex w-full min-h-12 items-center justify-center rounded-lg px-3 font-medium hover:bg-black/5 dark:hover:bg-white/10 focus-visible:outline-2 focus-visible:outline-purple-600 cursor-pointer" @onclick="@(() => sheetOpen = false)">Cancel</button>
        </li>
    </ul>
</TwDrawer>
<p role="status" class="mt-3 text-sm">@sheetStatus</p>
CSHARP
@code {
    private bool sheetOpen;
    private string sheetStatus = string.Empty;
    
    private readonly (Icon Icon, string Label)[] sheetActions =
    [
        (Icon.Copy, "Copy link"),
        (Icon.Download, "Download"),
        (Icon.Files, "Make a copy"),
        (Icon.Trash, "Move to bin")
    ];
    
    private void RunAction(string label)
    {
        sheetStatus = $"{label} chosen.";
        sheetOpen = false;
    }
}

Non-modal side sheet

Set Modal="false" for a side sheet that sits over the page without blocking it: there is no backdrop, Tab can leave the drawer, and the page behind it still scrolls and responds. Use it for details or help that people read alongside their work. Escape and the close button still close it.
RAZOR
<TwButton Label="@(helpOpen ? "Hide help" : "Show help")" StartIcon="Icon.Layout_Sidebar_Reverse" Variant="ButtonVariant.Outlined" OnClick="@(() => helpOpen = !helpOpen)" aria-expanded="@(helpOpen ? "true" : "false")" />

<TwDrawer @bind-Open="helpOpen" Modal="false" Size="DrawerSize.Small" Title="Help" Description="Keep this open while you work.">
    <p class="mb-3">Drawers suit content that relates to the page without replacing it, such as a record's details or a list of filters.</p>
    <p>Unlike a dialog, a drawer keeps the page in sight, so people don't lose their place.</p>
</TwDrawer>
CSHARP
@code {
    private bool helpOpen;
}

Opening from code

Call OpenAsync, CloseAsync and ToggleAsync on a reference to the drawer, or set the bound value. Set CloseOnBackdropClick="false" where a stray click could lose work: Escape, the close button and the footer still close it. Put data-tw-autofocus on the element that should take focus when the drawer opens.
RAZOR
<TwButton Label="New note" OnClick="@(() => noteDrawer.OpenAsync())" />

<TwDrawer @ref="noteDrawer" Title="New note" Size="DrawerSize.Large" CloseOnBackdropClick="false">
    <ChildContent>
        <TwTextfield T="string" Label="Note" @bind-Value="noteText" data-tw-autofocus />
    </ChildContent>
    <FooterContent>
        <TwButton Label="Discard" Variant="ButtonVariant.Outlined" OnClick="@DiscardNoteAsync" />
        <TwButton Label="Save note" OnClick="@(() => noteDrawer.CloseAsync())" />
    </FooterContent>
</TwDrawer>
CSHARP
@code {
    private TwDrawer noteDrawer = null!;
    private string noteText = string.Empty;
    
    private async Task DiscardNoteAsync()
    {
        noteText = string.Empty;
        await noteDrawer.CloseAsync();
    }
}

Accessibility

The panel is a dialog named by its Title (or AriaLabel) and described by its Description. Opening it moves focus inside: onto an element marked data-tw-autofocus, else the first control in its body or footer, else the panel itself so its name is read out. A modal drawer keeps Tab inside it, makes the page behind it inert and stops the page scrolling; toasts stay reachable. Escape closes it wherever focus is, and closing it returns focus to the control that opened it. While closed, the panel is hidden from assistive technology and out of the Tab order. The slide is turned off when the operating system asks for reduced motion. A dialog opened from inside a drawer, such as a confirmation, works as usual and Escape closes it first.

Keyboard navigation

The drawer is a dialog. Opening it moves focus inside, and closing it returns focus to the control that opened it. While a modal drawer is open the page behind it cannot be reached.
Key What it does
Tab Moves to the next control in the drawer. In a modal drawer, from the last control it wraps to the first.
Shift+ plus Tab Moves to the previous control in the drawer. In a modal drawer, from the first control it wraps to the last.
Enter or Space On the close button: closes the drawer.
Escape Closes the drawer, wherever focus is. If a picker, a select list or a dialog is open inside the drawer, the first press closes that and the next press closes the drawer. Has no effect when CloseOnEscape is off.

Theme configuration

Styling is controlled by TwBlazorTheme.Components (a TwDrawerTheme), configured via the AddTwBlazor() options callback described on the Get Started page. Every property is a set of Tailwind classes, so changes are picked up by your own Tailwind build.
Property Type Controls
Root string
Backdrop string
Panel string
Start string
End string
Top string
Bottom string
SmallWidth string
MediumWidth string
LargeWidth string
FullWidth string
SmallHeight string
MediumHeight string
LargeHeight string
FullHeight string
Header string
Heading string
Title string
Description string
CloseButton string
Content string
Footer string

Full reference: TwDrawerTheme on the API docs.

On this page

  • Basic usage
  • Position
  • Size
  • Action sheet
  • Non-modal side sheet
  • Opening from code
  • Accessibility
  • Keyboard navigation
  • Theme configuration
twblazor

The Tailwind CSS component library for Blazor. Accessible, themeable and MIT licensed.

Discord (opens in a new tab) GitHub (opens in a new tab)

Get started

  • Install guide
  • Theming
  • Class merging
  • Localization

Guides

  • Tailwind CSS with Blazor
  • Why twblazor?
  • Right to left
  • AI agents and skills

Resources

  • API documentation (opens in a new tab)
  • llms.txt (opens in a new tab)
  • MIT License (opens in a new tab)

Community

  • Contributing (opens in a new tab)
  • Code of conduct (opens in a new tab)
  • Report an issue (opens in a new tab)

twblazor is and always will be free and open source.

An unhandled error has occurred. Reload