Starting Point
v0.33.0

Search documentation

Search for a page and jump to it.

Start typing to search...
Go to Page
escClose

Sheet

The sheet slides a modal panel in from a screen edge. Use it for edit forms, filters, carts, and mobile navigation; for a centered window, reach for the dialog.

<button id="sheet-1-trigger" class="btn btn-outline">Open</button>
 
<dialog class="sheet" data-sp-toggle="#sheet-1-trigger">
  <div class="sheet-panel">
    <button
      class="btn btn-ghost btn-xs btn-icon absolute top-3 right-3"
      aria-label="Close"
      data-sp-dismiss
    >
      <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="size-4"><path d="M18 6 6 18"/><path d="m6 6 12 12"/></svg>
    </button>
    <div class="sheet-header">
      <h2 class="sheet-title">Edit profile</h2>
      <p class="sheet-description">
        Make changes to your profile here. Click save when you're done.
      </p>
    </div>
    <div class="sheet-content">
      <div class="field-group">
        <div class="field">
          <label class="label" for="sheet-profile-name">Name</label>
          <input class="input" id="sheet-profile-name" value="Pedro Duarte" />
        </div>
        <div class="field">
          <label class="label" for="sheet-profile-username">Username</label>
          <input class="input" id="sheet-profile-username" value="@peduarte" />
        </div>
      </div>
    </div>
    <div class="sheet-footer">
      <button class="btn">Save changes</button>
      <button class="btn btn-outline" data-sp-dismiss>Close</button>
    </div>
  </div>
</dialog>

Usage

Add the sheet class to a <dialog> element. Give your trigger an id, then point the sheet at it with data-sp-toggle. The trigger can be any element. Close the sheet with data-sp-dismiss on a button, a backdrop click, or the Escape key.

ClassDescription
sheetAdd to the <dialog> element; fills the viewport and dims the page
sheet-start sheet-end sheet-top sheet-bottomAdd to sheet to pick the edge; end is the default. sheet-left and sheet-right pin a physical edge
sheet-panelAdd to the child element that is the visible panel
sheet-headerAdd to the block holding the title and description
sheet-titleAdd to a heading element to create the sheet title
sheet-descriptionAdd to a paragraph to create the supporting description
sheet-contentAdd to the body section between header and footer
sheet-footerAdd to the action block; it sticks to the bottom of the panel
<!-- This is a button toggling the sheet -->
<button id="my-trigger" class="btn btn-outline">Open Sheet</button>
 
<!-- This is the sheet -->
<dialog class="sheet" data-sp-toggle="#my-trigger">
  <div class="sheet-panel">
    <div class="sheet-header">
      <h2 class="sheet-title">Title</h2>
      <p class="sheet-description">Description</p>
    </div>
    <div class="sheet-footer">
      <button class="btn btn-outline" data-sp-dismiss>Close</button>
    </div>
  </div>
</dialog>

Examples

Side

Pick the edge the sheet slides from with sheet-start, sheet-end, sheet-top, or sheet-bottom; start and end follow the text direction, and sheet-left or sheet-right pin a physical edge. Without one, it defaults to the end.

<!-- Start -->
<button id="side-left" class="btn btn-outline">Start</button>
 
<dialog class="sheet sheet-start" data-sp-toggle="#side-left">
  <div class="sheet-panel">
    <div class="sheet-header">
      <h2 class="sheet-title">Start</h2>
      <p class="sheet-description">Great for navigation menus.</p>
    </div>
    <div class="sheet-footer">
      <button class="btn btn-outline" data-sp-dismiss>Close</button>
    </div>
  </div>
</dialog>
 
<!-- End -->
<button id="side-right" class="btn btn-outline">End</button>
 
<dialog class="sheet sheet-end" data-sp-toggle="#side-right">
  <div class="sheet-panel">
    <div class="sheet-header">
      <h2 class="sheet-title">End</h2>
      <p class="sheet-description">Great for details and settings.</p>
    </div>
    <div class="sheet-footer">
      <button class="btn btn-outline" data-sp-dismiss>Close</button>
    </div>
  </div>
</dialog>
 
<!-- Top -->
<button id="side-top" class="btn btn-outline">Top</button>
 
<dialog class="sheet sheet-top" data-sp-toggle="#side-top">
  <div class="sheet-panel">
    <div class="sheet-header">
      <h2 class="sheet-title">Top</h2>
      <p class="sheet-description">Great for notifications.</p>
    </div>
    <div class="sheet-footer">
      <button class="btn btn-outline self-start" data-sp-dismiss>Close</button>
    </div>
  </div>
</dialog>
 
<!-- Bottom -->
<button id="side-bottom" class="btn btn-outline">Bottom</button>
 
<dialog class="sheet sheet-bottom" data-sp-toggle="#side-bottom">
  <div class="sheet-panel">
    <div class="sheet-header">
      <h2 class="sheet-title">Bottom</h2>
      <p class="sheet-description">Great for actions on mobile.</p>
    </div>
    <div class="sheet-footer">
      <button class="btn btn-outline self-start" data-sp-dismiss>Close</button>
    </div>
  </div>
</dialog>

Mobile navigation

Pair a start-side sheet with the sidebar menu classes for a simple mobile navigation drawer. For a full navigation layout with a desktop column, reach for the sidebar component instead.

<button id="sheet-nav-trigger" class="btn btn-ghost btn-icon" aria-label="Open menu">
  <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M4 12h16"/><path d="M4 18h16"/><path d="M4 6h16"/></svg>
</button>
 
<dialog class="sheet sheet-start" aria-label="Main menu" data-sp-toggle="#sheet-nav-trigger">
  <div class="sheet-panel">
    <button
      class="btn btn-ghost btn-xs btn-icon absolute top-3 right-3"
      aria-label="Close"
      data-sp-dismiss
    >
      <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="size-4"><path d="M18 6 6 18"/><path d="m6 6 12 12"/></svg>
    </button>
    <div class="sheet-header">
      <a href="#" class="flex h-10 min-w-0 items-center gap-2 text-foreground">
        <span class="flex size-6 shrink-0 items-center justify-center overflow-hidden rounded-sm bg-primary text-base leading-none text-primary-foreground">
          <i class="font-serif font-bold not-italic">A</i>
        </span>
        <span class="truncate text-sm font-medium">Acme Inc.</span>
      </a>
    </div>
    <div class="sheet-content px-2">
      <nav class="sidebar-menu">
        <div class="sidebar-menu-item">
          <a href="#" class="sidebar-menu-button active">
            <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M15 21v-8a1 1 0 0 0-1-1h-4a1 1 0 0 0-1 1v8"/><path d="M3 10a2 2 0 0 1 .709-1.528l7-5.999a2 2 0 0 1 2.582 0l7 5.999A2 2 0 0 1 21 10v9a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z"/></svg>
            <span>Home</span>
          </a>
        </div>
        <div class="sidebar-menu-item">
          <a href="#" class="sidebar-menu-button">
            <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M22 12h-6l-2 3h-4l-2-3H2"/><path d="M5.45 5.11 2 12v6a2 2 0 0 0 2 2h16a2 2 0 0 0 2-2v-6l-3.45-6.89A2 2 0 0 0 16.76 4H7.24a2 2 0 0 0-1.79 1.11z"/></svg>
            <span>Inbox</span>
          </a>
        </div>
        <div class="sidebar-menu-item">
          <a href="#" class="sidebar-menu-button">
            <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M8 2v4"/><path d="M16 2v4"/><rect width="18" height="18" x="3" y="4" rx="2"/><path d="M3 10h18"/></svg>
            <span>Calendar</span>
          </a>
        </div>
        <div class="sidebar-menu-item">
          <a href="#" class="sidebar-menu-button">
            <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M12.22 2h-.44a2 2 0 0 0-2 2v.18a2 2 0 0 1-1 1.73l-.43.25a2 2 0 0 1-2 0l-.15-.08a2 2 0 0 0-2.73.73l-.22.38a2 2 0 0 0 .73 2.73l.15.1a2 2 0 0 1 1 1.72v.51a2 2 0 0 1-1 1.74l-.15.09a2 2 0 0 0-.73 2.73l.22.38a2 2 0 0 0 2.73.73l.15-.08a2 2 0 0 1 2 0l.43.25a2 2 0 0 1 1 1.73V20a2 2 0 0 0 2 2h.44a2 2 0 0 0 2-2v-.18a2 2 0 0 1 1-1.73l.43-.25a2 2 0 0 1 2 0l.15.08a2 2 0 0 0 2.73-.73l.22-.39a2 2 0 0 0-.73-2.73l-.15-.08a2 2 0 0 1-1-1.74v-.5a2 2 0 0 1 1-1.74l.15-.09a2 2 0 0 0 .73-2.73l-.22-.38a2 2 0 0 0-2.73-.73l-.15.08a2 2 0 0 1-2 0l-.43-.25a2 2 0 0 1-1-1.73V4a2 2 0 0 0-2-2z"/><circle cx="12" cy="12" r="3"/></svg>
            <span>Settings</span>
          </a>
        </div>
 
      </nav>
    </div>
    <div class="sheet-footer">
      <button class="btn">Upgrade to Pro</button>
    </div>
  </div>
</dialog>

RTL

Add dir="rtl" to any parent element, typically <html>, to render right-to-left. See the RTL guide for details.

<div id="sheet-rtl-demo" dir="rtl">
  <button id="sheet-rtl-trigger" class="btn btn-outline" data-i18n="open">فتح</button>
 
  <dialog class="sheet" data-sp-toggle="#sheet-rtl-trigger">
    <div class="sheet-panel">
      <div class="sheet-header">
        <h2 class="sheet-title" data-i18n="editProfile">تعديل الملف الشخصي</h2>
        <p class="sheet-description" data-i18n="description">قم بإجراء تغييرات على ملفك الشخصي هنا. انقر حفظ عند الانتهاء.</p>
      </div>
      <div class="sheet-content">
        <div class="field-group">
          <div class="field">
            <label class="label" for="sheet-rtl-name" data-i18n="name">الاسم</label>
            <input class="input" id="sheet-rtl-name" value="Pedro Duarte" />
          </div>
          <div class="field">
            <label class="label" for="sheet-rtl-username" data-i18n="username">اسم المستخدم</label>
            <input class="input" id="sheet-rtl-username" value="@peduarte" />
          </div>
        </div>
      </div>
      <div class="sheet-footer">
        <button class="btn" data-i18n="save">حفظ التغييرات</button>
        <button class="btn btn-outline" data-sp-dismiss data-i18n="close">إغلاق</button>
      </div>
    </div>
  </dialog>
</div>
 
<script>
  const translations = {
    ar: { dir: "rtl", open: "فتح", editProfile: "تعديل الملف الشخصي", description: "قم بإجراء تغييرات على ملفك الشخصي هنا. انقر حفظ عند الانتهاء.", name: "الاسم", username: "اسم المستخدم", save: "حفظ التغييرات", close: "إغلاق" },
    he: { dir: "rtl", open: "פתח", editProfile: "עריכת פרופיל", description: "בצע שינויים בפרופיל שלך כאן. לחץ שמור כשתסיים.", name: "שם", username: "שם משתמש", save: "שמור שינויים", close: "סגור" },
    en: { dir: "ltr", open: "Open", editProfile: "Edit profile", description: "Make changes to your profile here. Click save when you're done.", name: "Name", username: "Username", save: "Save changes", close: "Close" },
  };
  window.addEventListener("message", (e) => {
    const t = translations[e.data?.lang];
    if (e.data?.type !== "sp-language" || !t) return;
    document.getElementById("sheet-rtl-demo").dir = t.dir;
    document.querySelectorAll("[data-i18n]").forEach((el) => {
      el.textContent = t[el.dataset.i18n];
    });
  });
</script>

Options

Sheet

Set each option with its own data-sp-* attribute on the sheet element.

AttributeValuesDefault
data-sp-toggleCSS selector
data-sp-staticBooleanfalse
<dialog class="sheet" data-sp-toggle="#my-trigger" data-sp-static>

JavaScript

Events

Lifecycle events fire on the sheet element; before* events are cancelable.

EventWhen
sp-beforeshowBefore showing (cancelable)
sp-showOpening
sp-shownOpen and settled
sp-beforehideBefore hiding (cancelable)
sp-hideClosing
sp-hiddenClosed
sp-hidepreventedA static sheet refused a backdrop dismiss
el.addEventListener("sp-beforeshow", (e) => {
  if (!ready) e.preventDefault(); // veto the open
});

Methods

Get the instance with sp.sheet(el), then call its methods:

MethodDescription
show()Open the sheet
hide()Close the sheet
toggle()Open if closed, else close
const sheet = sp.sheet(document.querySelector("#my-sheet"));
 
sheet.show();