MD3
Expressive
MATERIAL DESIGN 3 EXPRESSIVE

Side sheets

Side sheets show secondary content anchored to the side of the screen.

Side sheets display supplementary surfaces mostly in medium and expanded window sizes (like tablet and desktop). They provide a consistent and predictable surface for contextual actions, navigation, or filters.

Introduction

Material Design 3 Expressive Side Sheets are panels that slide in from the screen edges (usually on the right side). They have a fixed width and span the full height of the viewport.

We support two variants:

  • Standard side sheets: Co-exist alongside primary content. They can be coplanar (pushing main content to adapt layout) or overlay.
  • Modal side sheets: Block background interaction on smaller viewports, using a Scrim to lock attention.

Anatomy

  • Container: The full-height container.
  • Headline: The header area describing the sheet's purpose.
  • Close / Back Button (Optional): Provides a quick way to dismiss the sheet.
  • Divider (Optional): Groups content and separates actions from core details.
  • Scrim (Modal only): A semi-transparent overlay blocking underneath interaction.

Variants

Standard Side Sheet

Standard side sheets co-exist with the page. You can supply a coplanarSiblingRef to automatically resize the page content alongside the sheet.

The demo below illustrates a coplanar side sheet displaying file metadata information that pushes page content to adapt dynamically.

Loading demo...

Modal side sheets block background interaction using a Scrim, making them great for filters or detailed forms on mobile and tablet.

The demo below presents a modal side sheet dimmed with a background scrim, overlaying page content.

Loading demo...

Responsive Adaptive Sheet

By combining bottom and side sheets with responsive hooks, you can automatically present a Bottom Sheet Modal on mobile and transition to a Side Sheet Modal on desktop.

Loading demo...

Features

Sibling Resizing (Coplanar Layout)

The standard side sheet supports Option D (Coplanar sibling) from the MD3 spec. Pass coplanarSiblingRef with a ref pointing to your main container, and its margin will automatically transition to make space for the side sheet.

Edge Support

Sheets can slide in from either the start (left in LTR) or end (right in LTR) edge. For right-to-left (RTL) locales, they automatically adapt.

Usage

import { SideSheet, SideSheetModal } from "@bug-on/m3-expressive";
import { useRef, useState } from "react";


export function Example() {
  const [standardOpen, setStandardOpen] = useState(false);
  const [modalOpen, setModalOpen] = useState(false);
  const mainRef = useRef<HTMLDivElement>(null);

  return (
    <div className="flex">
      <main ref={mainRef} className="flex-1">
        Main page content
      </main>

      {/* Standard Side Sheet */}
      <SideSheet 
        isOpen={standardOpen} 
        onClose={() => setStandardOpen(false)}
        coplanarSiblingRef={mainRef}
        edge="end"
      >
        <div>Standard content</div>
      </SideSheet>

      {/* Modal Side Sheet */}
      <SideSheetModal
        isOpen={modalOpen}
        onClose={() => setModalOpen(false)}
        edge="end"
      >
        <div>Modal content</div>
      </SideSheetModal>
    </div>
  );
}

Best Practices

Do

  • Place side sheets along the right edge to avoid interference with left navigation.
  • Use Standard side sheets for medium/expanded screens (tablet, desktop).
  • Include a close icon button for easy dismissal.
  • Reverse side sheet directions to the left side in RTL locales.

Don't

  • Don't enable horizontal scrolling inside a side sheet; keep layout simple.
  • Don't overlay navigation bars with standard side sheets.
  • Avoid using modal side sheets on small viewports unless necessary (use bottom sheets instead).

Design Tokens

Geometry

Side sheets do not have rounded corners by default when docked to the screen edges, except when slightly offset.

Motion

AnimationSpring TokenTier
Slide In / OutDEFAULT_SPATIAL_SPRINGDefault

Accessibility

  • Keyboard Support: Full keyboard trap on modal variant. Escape dismisses the modal side sheet automatically.
  • Roles: Standard variant uses role="complementary" while modal uses role="dialog".
  • Focus Restoration: Focus returns to the trigger button when the sheet is closed.

API Reference

SideSheet / SideSheetModal

PropTypeDefaultDescription
isOpenbooleanRequired. Controlled open state.
onClose() => voidRequired. Callback triggered on dismissal.
edge"start" | "end""end"Screen edge to slide in from (start = left, end = right in LTR).
widthstring"360px"Custom width of the sheet container.
coplanarSiblingRefReact.RefObject<HTMLElement>Standard only: Ref of sibling container to apply margin compression.
headerReactNodeStatic header content rendered at the top of the sheet.
footerReactNodeStatic footer content rendered at the bottom of the sheet.
dividerboolean | { header?: boolean; footer?: boolean }trueDivider line display configuration.

| scrollAreaProps | Omit<ScrollAreaProps, "children"> | — | Custom settings for the internal Radix ScrollArea (e.g. type="hover" for modern scrollbars). | | className | string | — | Custom Tailwind CSS styling classes. | | aria-labelledby | string | — | Target title ID for screen reader dialogue header. | | aria-label | string | — | Screen reader announcement text. |