Skip to content

Drawer

Panel that slides in from an edge of the screen.

Browsers
Chrome 123+Firefox 121+Safari 17.5+
Tier
0
Bundle compressed
4.01 kB
Forced layout budget
0 ms
Axe budget
0
SSR compatible
Yes
Built on
elements/dialog
Published contract
Test harness

Playground

Drawer

Closed

Settings

Adjust your workspace preferences.

On smaller screens this panel becomes a bottom sheet. Swipe down from the handle, click the backdrop or use Close.

Snap points

Activity

Drag the handle to expand or dismiss the sheet.

Recent activity appears here.

Widths

SM drawer

Native dialog controls work before hydration.

On a phone, this becomes a bottom sheet.

MD drawer

Native dialog controls work before hydration.

On a phone, this becomes a bottom sheet.

LG drawer

Native dialog controls work before hydration.

On a phone, this becomes a bottom sheet.

FULL drawer

Native dialog controls work before hydration.

On a phone, this becomes a bottom sheet.

Sides

Workspace settings

Adjust workspace preferences.

Workspace settings

Adjust workspace preferences.

Workspace settings

Adjust workspace preferences.

Workspace settings

Adjust workspace preferences.

import { DrawerPanel } from "@gunkin/uiify";

export default function Example() {
  return (
    <div className="">
      <DrawerPanel
        id="settings-drawer"
        side="right"
        trigger="Open settings"
        title="Settings"
        description="Adjust your preferences."
      />
    </div>
  );
}
@layer components {
  [data-uiify-drawer][data-part="content"] {
    --uiify-drawer-inline-size: 32rem;

    margin: 0;
    inline-size: 100%;
    max-inline-size: 100%;
    max-block-size: 100dvh;
    padding: var(--space-xl);
    border: var(--border-width) solid var(--border);
    background: var(--popover);
    color: var(--popover-foreground);
    box-shadow: var(--shadow-modal);
    flex-direction: column;
    gap: var(--space-md);
  }
  [data-uiify-drawer][data-part="content"][open] {
    display: flex;
  }
  [data-uiify-drawer][data-size="sm"] {
    --uiify-drawer-inline-size: 24rem;
  }
  [data-uiify-drawer][data-size="lg"] {
    --uiify-drawer-inline-size: 40rem;
  }
  [data-uiify-drawer][data-size="full"] {
    --uiify-drawer-inline-size: 100%;
  }
  [data-uiify-drawer][data-part="content"]::backdrop {
    background: rgb(0 0 0 / 45%);
  }
  [data-uiify-drawer][data-backdrop="transparent"]::backdrop {
    background: transparent;
  }
  [data-uiify-drawer][data-part="content"][data-side="bottom"] {
    margin-block-start: auto;
    block-size: min(var(--uiify-drawer-inline-size), 80dvh);
    max-block-size: 80dvh;
    border-start-start-radius: var(--radius-xl);
    border-start-end-radius: var(--radius-xl);
    transform: var(--uiify-drawer-transform, none);
  }
  [data-uiify-drawer][data-part="content"][data-side="top"] {
    margin-block-end: auto;
    block-size: min(var(--uiify-drawer-inline-size), 80dvh);
    max-block-size: 80dvh;
    border-end-start-radius: var(--radius-xl);
    border-end-end-radius: var(--radius-xl);
    transform: var(--uiify-drawer-transform, none);
  }
  [data-uiify-drawer][data-part="content"]:is([data-side="left"], [data-side="right"]) {
    inline-size: min(var(--uiify-drawer-inline-size), 100%);
    block-size: 100dvh;
    transform: var(--uiify-drawer-transform, none);
  }
  [data-uiify-drawer][data-part="content"][data-side="left"] {
    margin-inline-end: auto;
  }
  [data-uiify-drawer][data-part="content"][data-side="right"] {
    margin-inline-start: auto;
    border-start-end-radius: 0;
    border-end-end-radius: 0;
  }
  :dir(rtl) [data-uiify-drawer][data-part="content"][data-side="left"] {
    margin-inline: auto 0;
  }
  :dir(rtl) [data-uiify-drawer][data-part="content"][data-side="right"] {
    margin-inline: 0 auto;
  }
  [data-uiify-drawer][data-part="content"][data-size="full"] {
    inline-size: 100dvi;
    max-inline-size: 100dvi;
    block-size: 100dvh;
    max-block-size: 100dvh;
  }
  [data-uiify-drawer] [data-part="header"] {
    position: relative;
    flex: none;
    padding-inline-end: 2.75rem;
  }
  [data-uiify-drawer] [data-part="body"] {
    min-block-size: 0;
    overflow: auto;
    overscroll-behavior: contain;
    touch-action: pan-y;
  }
  [data-uiify-drawer] [data-part="footer"] {
    display: flex;
    flex-wrap: wrap;
    justify-content: flex-end;
    gap: var(--space-sm);
  }
  [data-uiify-drawer] [data-part="close"] {
    display: inline-grid;
    place-items: center;
    inline-size: 2.25rem;
    block-size: 2.25rem;
    padding: 0;
    border: 0;
    border-radius: 50%;
    corner-shape: round;
    background: var(--secondary);
    color: var(--secondary-foreground);
  }
  [data-uiify-drawer] [data-part="header"] > [data-part="close"] {
    position: absolute;
    inset-block-start: 0;
    inset-inline-end: 0;
  }
  [data-uiify-drawer] :is([data-part="grabber"], [data-part="handle"]) {
    display: none;
    flex: none;
    block-size: 1.5rem;
    touch-action: none;
  }
  [data-uiify-drawer] :is([data-part="grabber"], [data-part="handle"])::after {
    content: "";
    display: block;
    inline-size: 2.25rem;
    block-size: 0.25rem;
    margin-block: 0.5rem 0;
    margin-inline: auto;
    border-radius: 999px;
    background: var(--border);
  }
  [data-uiify-drawer][data-snap-enabled] [data-part="handle"] {
    display: block;
  }

  @media (width < 40rem) {
    [data-uiify-drawer][data-part="content"][data-side] {
      inline-size: 100dvi;
      max-inline-size: 100dvi;
      block-size: auto;
      min-block-size: 50dvh;
      max-block-size: 80dvh;
      margin-block: auto 0;
      margin-inline: 0;
      border-start-start-radius: var(--radius-xl);
      border-start-end-radius: var(--radius-xl);
      border-end-start-radius: 0;
      border-end-end-radius: 0;
      transform: var(--uiify-drawer-transform, none);
      translate: 0 var(--uiify-sheet-offset, 0);
      padding-block-end: calc(var(--space-xl) + env(safe-area-inset-bottom));
    }
    [data-uiify-drawer][data-part="content"][data-size="full"] {
      block-size: 100dvh;
      max-block-size: 100dvh;
      border-radius: 0;
    }
    [data-uiify-drawer] :is([data-part="grabber"], [data-part="handle"]) {
      display: block;
    }
    [data-uiify-drawer] [data-part="header"] {
      touch-action: none;
    }
    [data-uiify-drawer][data-dragging] {
      transition: none;
    }
  }

  @media (prefers-reduced-motion: no-preference) {
    [data-uiify-drawer][data-part="content"] {
      transition:
        opacity 180ms ease,
        translate 220ms ease,
        transform 220ms ease,
        display 220ms allow-discrete,
        overlay 220ms allow-discrete;
    }
    [data-uiify-drawer][data-part="content"]:not([open]) {
      opacity: 0;
    }

    @starting-style {
      [data-uiify-drawer][data-part="content"][open] {
        opacity: 0;
      }
    }
  }
}
import { DrawerPanel } from "@gunkin/uiify";

export default function Example() {
  return (
    <div
      className={
        "[&[data-positioning=native]]:[--uiify-anchor-offset:var(--space-sm)] [&_[data-positioning=native]]:[--uiify" +
        "-anchor-offset:var(--space-sm)] [&[popover]:popover-open:not([data-positioning=native])]:[margin:revert] [&" +
        "_[popover]:popover-open:not([data-positioning=native])]:[margin:revert] [&_[data-uiify-drawer][data-part=tr" +
        "igger]]:relative [&_[data-uiify-drawer][data-part=trigger]]:inline-flex [&_[data-uiify-drawer][data-part=tr" +
        "igger]]:min-h-11 [&_[data-uiify-drawer][data-part=trigger]]:min-w-11 [&_[data-uiify-drawer][data-part=trigg" +
        "er]]:items-center [&_[data-uiify-drawer][data-part=trigger]]:justify-center [&_[data-uiify-drawer][data-par" +
        "t=trigger]]:rounded-full [&_[data-uiify-drawer][data-part=trigger]]:border-[length:var(--border-width)] [&_" +
        "[data-uiify-drawer][data-part=trigger]]:border-solid [&_[data-uiify-drawer][data-part=trigger]]:border-tran" +
        "sparent [&_[data-uiify-drawer][data-part=trigger]]:bg-foreground [&_[data-uiify-drawer][data-part=trigger]]" +
        ":px-5 [&_[data-uiify-drawer][data-part=trigger]]:py-0 [&_[data-uiify-drawer][data-part=trigger]]:text-backg" +
        "round [&_[data-uiify-drawer][data-part=trigger]]:text-base [&_[data-uiify-drawer][data-part=trigger]]:font-" +
        "medium [&_[data-uiify-drawer][data-part=trigger]]:leading-6 [&_[data-uiify-drawer][data-part=trigger]]:no-u" +
        "nderline [&_[data-uiify-drawer][data-part=trigger]]:cursor-pointer [&_[data-uiify-drawer][data-part=trigger" +
        "]]:[transition:var(--transition-colors)] [&_[data-uiify-drawer][data-part=content]]:[--uiify-drawer-inline-" +
        "size:32rem] [&_[data-uiify-drawer][data-size=sm][data-part=content]]:[--uiify-drawer-inline-size:24rem] [&_" +
        "[data-uiify-drawer][data-size=lg][data-part=content]]:[--uiify-drawer-inline-size:40rem] [&_[data-uiify-dra" +
        "wer][data-size=full][data-part=content]]:[--uiify-drawer-inline-size:100%] [&_[data-uiify-drawer][data-part" +
        "=content]]:m-0 [&_[data-uiify-drawer][data-part=content]]:w-full [&_[data-uiify-drawer][data-part=content]]" +
        ":max-w-full [&_[data-uiify-drawer][data-part=content]]:max-h-dvh [&_[data-uiify-drawer][data-part=content]]" +
        ":p-6 [&_[data-uiify-drawer][data-part=content]]:border [&_[data-uiify-drawer][data-part=content]]:border-bo" +
        "rder [&_[data-uiify-drawer][data-part=content]]:bg-popover [&_[data-uiify-drawer][data-part=content]]:text-" +
        "popover-foreground [&_[data-uiify-drawer][data-part=content]]:shadow-modal [&_[data-uiify-drawer][data-part" +
        "=content]]:flex-col [&_[data-uiify-drawer][data-part=content]]:gap-md [&_[data-uiify-drawer][data-part=cont" +
        "ent]]:rounded-xl [&_[data-uiify-drawer][data-part=content]]:[corner-shape:squircle] [&_[data-uiify-drawer][" +
        "data-part=content]::backdrop]:[background:rgb(0_0_0_/_45%)] [&_[data-uiify-drawer][data-part=content][data-" +
        "backdrop=transparent]::backdrop]:bg-transparent [&_[data-uiify-drawer][data-part=content][open]]:flex [&_[d" +
        "ata-uiify-drawer][data-part=content][data-side=right]]:ms-auto [&_[data-uiify-drawer][data-part=content][da" +
        "ta-side=left]]:me-auto [&_[data-uiify-drawer][data-part=content][data-side=top]]:mb-auto [&_[data-uiify-dra" +
        "wer][data-part=content][data-side=bottom]]:mt-auto [&_[data-uiify-drawer][data-part=content][data-side=bott" +
        "om]]:h-[min(var(--uiify-drawer-inline-size),_80dvh)] [&_[data-uiify-drawer][data-part=content][data-side=to" +
        "p]]:h-[min(var(--uiify-drawer-inline-size),_80dvh)] [&_[data-uiify-drawer][data-part=content][data-side=lef" +
        "t]]:w-[min(var(--uiify-drawer-inline-size),_100%)] [&_[data-uiify-drawer][data-part=content][data-side=righ" +
        "t]]:w-[min(var(--uiify-drawer-inline-size),_100%)] [&_[data-uiify-drawer][data-part=content]:is([data-side=" +
        "left],[data-side=right])]:[block-size:100dvh] [&_[data-uiify-drawer][data-part=content][data-side=right]]:[" +
        "border-start-end-radius:0] [&_[data-uiify-drawer][data-part=content][data-side=right]]:[border-end-end-radi" +
        "us:0] [&_[data-uiify-drawer][data-part=content][data-side=left]]:[border-start-start-radius:0] [&_[data-uii" +
        "fy-drawer][data-part=content][data-side=left]]:[border-end-start-radius:0] [&_[data-uiify-drawer][data-part" +
        "=content][data-size=full]]:[inline-size:100dvi] [&_[data-uiify-drawer][data-part=content][data-size=full]]:" +
        "[block-size:100dvh] [&_[data-uiify-drawer]_[data-part=header]]:relative [&_[data-uiify-drawer]_[data-part=h" +
        "eader]]:flex-none [&_[data-uiify-drawer]_[data-part=header]]:pe-11 [&_[data-uiify-drawer]_[data-part=body]]" +
        ":min-h-0 [&_[data-uiify-drawer]_[data-part=body]]:overflow-auto [&_[data-uiify-drawer]_[data-part=body]]:ov" +
        "erscroll-contain [&_[data-uiify-drawer]_[data-part=body]]:[touch-action:pan-y] [&_[data-uiify-drawer]_[data" +
        "-part=footer]]:flex [&_[data-uiify-drawer]_[data-part=footer]]:flex-wrap [&_[data-uiify-drawer]_[data-part=" +
        "footer]]:justify-end [&_[data-uiify-drawer]_[data-part=footer]]:gap-sm [&_[data-uiify-drawer]_[data-part=cl" +
        "ose]]:inline-grid [&_[data-uiify-drawer]_[data-part=close]]:place-items-center [&_[data-uiify-drawer]_[data" +
        "-part=close]]:size-9 [&_[data-uiify-drawer]_[data-part=close]]:p-0 [&_[data-uiify-drawer]_[data-part=close]" +
        "]:border-0 [&_[data-uiify-drawer]_[data-part=close]]:rounded-full [&_[data-uiify-drawer]_[data-part=close]]" +
        ":bg-secondary [&_[data-uiify-drawer]_[data-part=close]]:text-secondary-foreground [&_[data-uiify-drawer]_[d" +
        "ata-part=close]]:cursor-pointer [&_[data-uiify-drawer]_[data-part=header]>[data-part=close]]:absolute [&_[d" +
        "ata-uiify-drawer]_[data-part=header]>[data-part=close]]:[inset-block-start:0] [&_[data-uiify-drawer]_[data-" +
        "part=header]>[data-part=close]]:[inset-inline-end:0] [&_[data-uiify-drawer]_:is([data-part=grabber],[data-p" +
        "art=handle])]:hidden [&_[data-uiify-drawer]_:is([data-part=grabber],[data-part=handle])]:flex-none [&_[data" +
        "-uiify-drawer]_:is([data-part=grabber],[data-part=handle])]:[block-size:1.5rem] [&_[data-uiify-drawer]_:is(" +
        "[data-part=grabber],[data-part=handle])]:[touch-action:none] [&_[data-uiify-drawer]_:is([data-part=grabber]" +
        ",[data-part=handle])]:after:content-[''] [&_[data-uiify-drawer]_:is([data-part=grabber],[data-part=handle])" +
        "]:after:block [&_[data-uiify-drawer]_:is([data-part=grabber],[data-part=handle])]:after:w-9 [&_[data-uiify-" +
        "drawer]_:is([data-part=grabber],[data-part=handle])]:after:h-1 [&_[data-uiify-drawer]_:is([data-part=grabbe" +
        "r],[data-part=handle])]:after:[margin-block:0.5rem_0] [&_[data-uiify-drawer]_:is([data-part=grabber],[data-" +
        "part=handle])]:after:mx-auto [&_[data-uiify-drawer]_:is([data-part=grabber],[data-part=handle])]:after:roun" +
        "ded-full [&_[data-uiify-drawer]_:is([data-part=grabber],[data-part=handle])]:after:bg-border max-[40rem]:[&" +
        "_[data-uiify-drawer][data-part=content][data-side]]:[inline-size:100dvi] max-[40rem]:[&_[data-uiify-drawer]" +
        "[data-part=content][data-side]]:[block-size:auto] max-[40rem]:[&_[data-uiify-drawer][data-part=content][dat" +
        "a-side]]:[min-block-size:50dvh] max-[40rem]:[&_[data-uiify-drawer][data-part=content][data-side]]:[max-bloc" +
        "k-size:80dvh] max-[40rem]:[&_[data-uiify-drawer][data-part=content][data-side]]:[margin-block:auto_0] max-[" +
        "40rem]:[&_[data-uiify-drawer][data-part=content][data-side]]:[margin-inline:0] max-[40rem]:[&_[data-uiify-d" +
        "rawer][data-part=content][data-side]]:[border-start-start-radius:var(--radius-xl)] max-[40rem]:[&_[data-uii" +
        "fy-drawer][data-part=content][data-side]]:[border-start-end-radius:var(--radius-xl)] max-[40rem]:[&_[data-u" +
        "iify-drawer][data-part=content][data-side]]:[border-end-start-radius:0] max-[40rem]:[&_[data-uiify-drawer][" +
        "data-part=content][data-side]]:[border-end-end-radius:0] max-[40rem]:[&_[data-uiify-drawer][data-part=conte" +
        "nt][data-side]]:[padding-block-end:calc(var(--space-xl)_+_env(safe-area-inset-bottom))] max-[40rem]:[&_[dat" +
        "a-uiify-drawer]_:is([data-part=grabber],[data-part=handle])]:block max-[40rem]:[&_[data-uiify-drawer]_[data" +
        "-part=header]]:[touch-action:none] [&_[data-uiify-drawer][data-part=title]]:m-0 [&_[data-uiify-drawer][data" +
        "-part=title]]:text-[length:var(--text-xl)] [&_[data-uiify-drawer][data-part=description]]:m-0 [&_[data-uiif" +
        "y-drawer][data-part=description]]:text-muted-foreground [&_[data-uiify-drawer][data-part=description]]:text" +
        "-sm [&_[data-uiify-drawer][data-part=handle]]:mx-auto [&_[data-uiify-drawer][data-part=handle]]:h-1 [&_[dat" +
        "a-uiify-drawer][data-part=handle]]:w-10 [&_[data-uiify-drawer][data-part=handle]]:rounded-full [&_[data-uii" +
        "fy-drawer][data-part=handle]]:bg-muted-foreground"
      }
    >
      <DrawerPanel
        id="settings-drawer"
        side="right"
        trigger="Open settings"
        title="Settings"
        description="Adjust your preferences."
      />
    </div>
  );
}
/* app.css */

@layer reset, ui, app, tokens, base, demo, components, utilities, theme;

@import "@gunkin/uiify/styles/reset";

@import "@gunkin/uiify/components/behavior.css";

@import "@gunkin/uiify/styles/tokens";

@import "@gunkin/uiify/styles/tailwind";

@import "tailwindcss/utilities.css";

@theme { --spacing: 0.25rem; --font-weight-normal: 400; --font-weight-medium: 500; --font-weight-semibold: 600; --font-weight-bold: 700; }

@source inline('[&[data-positioning=native]]:[--uiify-anchor-offset:var(--space-sm)] [&_[data-positioning=native]]:[--uiify-anchor-offset:var(--space-sm)] [&[popover]:popover-open:not([data-positioning=native])]:[margin:revert] [&_[popover]:popover-open:not([data-positioning=native])]:[margin:revert] [&_[data-uiify-drawer][data-part=trigger]]:relative [&_[data-uiify-drawer][data-part=trigger]]:inline-flex [&_[data-uiify-drawer][data-part=trigger]]:min-h-11 [&_[data-uiify-drawer][data-part=trigger]]:min-w-11 [&_[data-uiify-drawer][data-part=trigger]]:items-center [&_[data-uiify-drawer][data-part=trigger]]:justify-center [&_[data-uiify-drawer][data-part=trigger]]:rounded-full [&_[data-uiify-drawer][data-part=trigger]]:border-[length:var(--border-width)] [&_[data-uiify-drawer][data-part=trigger]]:border-solid [&_[data-uiify-drawer][data-part=trigger]]:border-transparent [&_[data-uiify-drawer][data-part=trigger]]:bg-foreground [&_[data-uiify-drawer][data-part=trigger]]:px-5 [&_[data-uiify-drawer][data-part=trigger]]:py-0 [&_[data-uiify-drawer][data-part=trigger]]:text-background [&_[data-uiify-drawer][data-part=trigger]]:text-base [&_[data-uiify-drawer][data-part=trigger]]:font-medium [&_[data-uiify-drawer][data-part=trigger]]:leading-6 [&_[data-uiify-drawer][data-part=trigger]]:no-underline [&_[data-uiify-drawer][data-part=trigger]]:cursor-pointer [&_[data-uiify-drawer][data-part=trigger]]:[transition:var(--transition-colors)] [&_[data-uiify-drawer][data-part=content]]:[--uiify-drawer-inline-size:32rem] [&_[data-uiify-drawer][data-size=sm][data-part=content]]:[--uiify-drawer-inline-size:24rem] [&_[data-uiify-drawer][data-size=lg][data-part=content]]:[--uiify-drawer-inline-size:40rem] [&_[data-uiify-drawer][data-size=full][data-part=content]]:[--uiify-drawer-inline-size:100%] [&_[data-uiify-drawer][data-part=content]]:m-0 [&_[data-uiify-drawer][data-part=content]]:w-full [&_[data-uiify-drawer][data-part=content]]:max-w-full [&_[data-uiify-drawer][data-part=content]]:max-h-dvh [&_[data-uiify-drawer][data-part=content]]:p-6 [&_[data-uiify-drawer][data-part=content]]:border [&_[data-uiify-drawer][data-part=content]]:border-border [&_[data-uiify-drawer][data-part=content]]:bg-popover [&_[data-uiify-drawer][data-part=content]]:text-popover-foreground [&_[data-uiify-drawer][data-part=content]]:shadow-modal [&_[data-uiify-drawer][data-part=content]]:flex-col [&_[data-uiify-drawer][data-part=content]]:gap-md [&_[data-uiify-drawer][data-part=content]]:rounded-xl [&_[data-uiify-drawer][data-part=content]]:[corner-shape:squircle] [&_[data-uiify-drawer][data-part=content]::backdrop]:[background:rgb(0_0_0_/_45%)] [&_[data-uiify-drawer][data-part=content][data-backdrop=transparent]::backdrop]:bg-transparent [&_[data-uiify-drawer][data-part=content][open]]:flex [&_[data-uiify-drawer][data-part=content][data-side=right]]:ms-auto [&_[data-uiify-drawer][data-part=content][data-side=left]]:me-auto [&_[data-uiify-drawer][data-part=content][data-side=top]]:mb-auto [&_[data-uiify-drawer][data-part=content][data-side=bottom]]:mt-auto [&_[data-uiify-drawer][data-part=content][data-side=bottom]]:h-[min(var(--uiify-drawer-inline-size),_80dvh)] [&_[data-uiify-drawer][data-part=content][data-side=top]]:h-[min(var(--uiify-drawer-inline-size),_80dvh)] [&_[data-uiify-drawer][data-part=content][data-side=left]]:w-[min(var(--uiify-drawer-inline-size),_100%)] [&_[data-uiify-drawer][data-part=content][data-side=right]]:w-[min(var(--uiify-drawer-inline-size),_100%)] [&_[data-uiify-drawer][data-part=content]:is([data-side=left],[data-side=right])]:[block-size:100dvh] [&_[data-uiify-drawer][data-part=content][data-side=right]]:[border-start-end-radius:0] [&_[data-uiify-drawer][data-part=content][data-side=right]]:[border-end-end-radius:0] [&_[data-uiify-drawer][data-part=content][data-side=left]]:[border-start-start-radius:0] [&_[data-uiify-drawer][data-part=content][data-side=left]]:[border-end-start-radius:0] [&_[data-uiify-drawer][data-part=content][data-size=full]]:[inline-size:100dvi] [&_[data-uiify-drawer][data-part=content][data-size=full]]:[block-size:100dvh] [&_[data-uiify-drawer]_[data-part=header]]:relative [&_[data-uiify-drawer]_[data-part=header]]:flex-none [&_[data-uiify-drawer]_[data-part=header]]:pe-11 [&_[data-uiify-drawer]_[data-part=body]]:min-h-0 [&_[data-uiify-drawer]_[data-part=body]]:overflow-auto [&_[data-uiify-drawer]_[data-part=body]]:overscroll-contain [&_[data-uiify-drawer]_[data-part=body]]:[touch-action:pan-y] [&_[data-uiify-drawer]_[data-part=footer]]:flex [&_[data-uiify-drawer]_[data-part=footer]]:flex-wrap [&_[data-uiify-drawer]_[data-part=footer]]:justify-end [&_[data-uiify-drawer]_[data-part=footer]]:gap-sm [&_[data-uiify-drawer]_[data-part=close]]:inline-grid [&_[data-uiify-drawer]_[data-part=close]]:place-items-center [&_[data-uiify-drawer]_[data-part=close]]:size-9 [&_[data-uiify-drawer]_[data-part=close]]:p-0 [&_[data-uiify-drawer]_[data-part=close]]:border-0 [&_[data-uiify-drawer]_[data-part=close]]:rounded-full [&_[data-uiify-drawer]_[data-part=close]]:bg-secondary [&_[data-uiify-drawer]_[data-part=close]]:text-secondary-foreground [&_[data-uiify-drawer]_[data-part=close]]:cursor-pointer [&_[data-uiify-drawer]_[data-part=header]>[data-part=close]]:absolute [&_[data-uiify-drawer]_[data-part=header]>[data-part=close]]:[inset-block-start:0] [&_[data-uiify-drawer]_[data-part=header]>[data-part=close]]:[inset-inline-end:0] [&_[data-uiify-drawer]_:is([data-part=grabber],[data-part=handle])]:hidden [&_[data-uiify-drawer]_:is([data-part=grabber],[data-part=handle])]:flex-none [&_[data-uiify-drawer]_:is([data-part=grabber],[data-part=handle])]:[block-size:1.5rem] [&_[data-uiify-drawer]_:is([data-part=grabber],[data-part=handle])]:[touch-action:none] [&_[data-uiify-drawer]_:is([data-part=grabber],[data-part=handle])]:after:block [&_[data-uiify-drawer]_:is([data-part=grabber],[data-part=handle])]:after:w-9 [&_[data-uiify-drawer]_:is([data-part=grabber],[data-part=handle])]:after:h-1 [&_[data-uiify-drawer]_:is([data-part=grabber],[data-part=handle])]:after:[margin-block:0.5rem_0] [&_[data-uiify-drawer]_:is([data-part=grabber],[data-part=handle])]:after:mx-auto [&_[data-uiify-drawer]_:is([data-part=grabber],[data-part=handle])]:after:rounded-full [&_[data-uiify-drawer]_:is([data-part=grabber],[data-part=handle])]:after:bg-border max-[40rem]:[&_[data-uiify-drawer][data-part=content][data-side]]:[inline-size:100dvi] max-[40rem]:[&_[data-uiify-drawer][data-part=content][data-side]]:[block-size:auto] max-[40rem]:[&_[data-uiify-drawer][data-part=content][data-side]]:[min-block-size:50dvh] max-[40rem]:[&_[data-uiify-drawer][data-part=content][data-side]]:[max-block-size:80dvh] max-[40rem]:[&_[data-uiify-drawer][data-part=content][data-side]]:[margin-block:auto_0] max-[40rem]:[&_[data-uiify-drawer][data-part=content][data-side]]:[margin-inline:0] max-[40rem]:[&_[data-uiify-drawer][data-part=content][data-side]]:[border-start-start-radius:var(--radius-xl)] max-[40rem]:[&_[data-uiify-drawer][data-part=content][data-side]]:[border-start-end-radius:var(--radius-xl)] max-[40rem]:[&_[data-uiify-drawer][data-part=content][data-side]]:[border-end-start-radius:0] max-[40rem]:[&_[data-uiify-drawer][data-part=content][data-side]]:[border-end-end-radius:0] max-[40rem]:[&_[data-uiify-drawer][data-part=content][data-side]]:[padding-block-end:calc(var(--space-xl)_+_env(safe-area-inset-bottom))] max-[40rem]:[&_[data-uiify-drawer]_:is([data-part=grabber],[data-part=handle])]:block max-[40rem]:[&_[data-uiify-drawer]_[data-part=header]]:[touch-action:none] [&_[data-uiify-drawer][data-part=title]]:m-0 [&_[data-uiify-drawer][data-part=title]]:text-[length:var(--text-xl)] [&_[data-uiify-drawer][data-part=description]]:m-0 [&_[data-uiify-drawer][data-part=description]]:text-muted-foreground [&_[data-uiify-drawer][data-part=description]]:text-sm [&_[data-uiify-drawer][data-part=handle]]:mx-auto [&_[data-uiify-drawer][data-part=handle]]:h-1 [&_[data-uiify-drawer][data-part=handle]]:w-10 [&_[data-uiify-drawer][data-part=handle]]:rounded-full [&_[data-uiify-drawer][data-part=handle]]:bg-muted-foreground');

@source inline("[&_[data-uiify-drawer]_:is([data-part=grabber],[data-part=handle])]:after:content-['']");

@layer base { :root { --uiify-control-text: var(--text-sm); } @media (pointer: coarse) { :root { --uiify-control-text: var(--text-base); } } }

/* Authored animation and registered properties used by the Tailwind skin.
 * Visual rules belong in utility recipes; only at-rule definitions live here. */
@layer components {
  @keyframes uiify-presence-in {
    from {
      opacity: 0;
      scale: var(--presence-scale);
    }
  }
}

@layer components {
  @keyframes uiify-presence-out {
    to {
      opacity: 0;
      scale: var(--presence-scale);
    }
  }
}

@property --uiify-spinner-tail {
  syntax: "<angle>";
  inherits: false;
  initial-value: 0deg;
}

@property --uiify-spinner-length {
  syntax: "<angle>";
  inherits: false;
  initial-value: 36deg;
}

@layer components {
  @keyframes uiify-spinner-rotate {
    to {
      transform: rotate(360deg);
    }
  }
}

@layer components {
  @keyframes uiify-spinner-orbit {
    0% {
      --uiify-spinner-tail: 0deg;
      --uiify-spinner-length: 36deg;
    }

    50% {
      --uiify-spinner-tail: 90deg;
      --uiify-spinner-length: 324deg;
    }

    100% {
      --uiify-spinner-tail: 360deg;
      --uiify-spinner-length: 36deg;
    }
  }
}

@layer components {
  @keyframes uiify-skeleton-pulse {
    50% {
      opacity: 0.45;
    }
  }
}

@layer components {
  @keyframes uiify-skeleton-shimmer {
    to {
      background-position: -200% 0;
    }
  }
}

@layer components {
  @keyframes uiify-skeleton-reveal {
    from {
      opacity: 0;
    }
    to {
      opacity: 1;
    }
  }
}

@property --candle-body-height {
  syntax: "<percentage>";
  inherits: true;
  initial-value: 0%;
}

@property --candle-body-top {
  syntax: "<percentage>";
  inherits: true;
  initial-value: 50%;
}

@property --candle-slot {
  syntax: "<percentage>";
  inherits: true;
  initial-value: 100%;
}

@property --candle-wick-height {
  syntax: "<percentage>";
  inherits: true;
  initial-value: 0%;
}

@property --candle-wick-top {
  syntax: "<percentage>";
  inherits: true;
  initial-value: 50%;
}

@property --candle-x {
  syntax: "<percentage>";
  inherits: true;
  initial-value: 0%;
}

@property --candle-scale {
  syntax: "<number>";
  inherits: true;
  initial-value: 1;
}

@property --line-y {
  syntax: "<percentage>";
  inherits: true;
  initial-value: 50%;
}

@property --line-prev-y {
  syntax: "<percentage>";
  inherits: true;
  initial-value: 50%;
}

@property --line-count {
  syntax: "<integer>";
  inherits: false;
  initial-value: 1;
}

@property --line-scale {
  syntax: "<number>";
  inherits: true;
  initial-value: 1;
}

@layer components {
  @keyframes uiify-otp-input-caret-blink {
    50% {
      opacity: 0;
    }
  }
}

API

DrawerPanel

PropTypeDefaultDescription
size"sm" | "md" | "lg" | "full""md"Desktop widths: 24rem, 32rem, 40rem or available width. On mobile every size becomes a vertical bottom sheet.
dismiss"any" | "closerequest" | "none""any"Native dismissal policy. Any permits backdrop, Escape and mobile downward swipe; none requires an explicit close control.
backdrop"opaque" | "transparent""opaque"Backdrop appearance; does not change modal semantics.
id*string—Unique dialog id that the trigger and close button target, so the drawer opens and closes before hydration.
trigger*ReactNode—Content of the button that opens the drawer.
title*ReactNode—Heading rendered inside the drawer and used as its accessible name.
descriptionReactNode—Supporting text rendered under the title and referenced by aria-describedby.
childrenReactNode—Body content placed between the description and the close button.
side"top" | "right" | "bottom" | "left""bottom"Edge the drawer slides in from.
closeLabelstring"Close"Accessible label for the circular close icon.
classNamestring—Class applied to the dialog element.

Drawer.Root (client)

PropTypeDefaultDescription
openboolean—Controlled open state.
defaultOpenboolean—Uncontrolled initial open state.
onOpenChangeDialogChangeHandler—Called with the next open state and the details of what caused the change.
side"top" | "right" | "bottom" | "left""bottom"Edge the drawer slides in from, which also sets the drag axis.
modalbooleantrueOpen with showModal() so the rest of the page is inert behind a backdrop.
dismissiblebooleantrueAllow a drag past the last snap point to close the drawer.
snapPointsreadonly number[]—Fractions of the drawer size the panel settles on when dragged.
activeSnapPointnumber—Controlled snap point, as one of the values in snapPoints.
defaultActiveSnapPointnumber—Uncontrolled initial snap point.
onSnapChange(snap: number) => void—Called with the snap point the drawer settled on.
childrenReactNode—The Trigger, Content and inner parts.

Drawer.Trigger (client)

PropTypeDefaultDescription
classNamestring—Class applied to the trigger button.
onClick(event: MouseEvent<HTMLButtonElement>) => void—Called when the trigger is clicked, before the drawer opens.
refRef<HTMLButtonElement>—Ref to the trigger button, which is refocused when the drawer closes.
childrenReactNode—Content of the trigger button.

Drawer.Content (client)

PropTypeDefaultDescription
classNamestring—Class applied to the dialog element.
styleCSSProperties—Inline style merged with the drag transform the drawer applies.
onCancelReactEventHandler<HTMLDialogElement>—Called on the native dialog cancel event, such as pressing Escape.
onCloseReactEventHandler<HTMLDialogElement>—Called on the native dialog close event.
refRef<HTMLDialogElement>—Ref to the dialog element.
childrenReactNode—Content of the drawer.

Drawer.Title (client)

PropTypeDefaultDescription
classNamestring—Class applied to the title element.
childrenReactNode—Content of the title, which becomes the drawer's accessible name.

Drawer.Description (client)

PropTypeDefaultDescription
classNamestring—Class applied to the description element.
childrenReactNode—Content of the description, referenced by aria-describedby.

Drawer.Close (client)

PropTypeDefaultDescription
classNamestring—Class applied to the close button.
onClick(event: MouseEvent<HTMLButtonElement>) => void—Called when the close button is clicked, before the drawer closes.
childrenReactNode—Content of the close button.

Drawer.Handle (client)

PropTypeDefaultDescription
classNamestring—Class applied to the drag handle.
onPointerDown(event: PointerEvent<HTMLDivElement>) => void—Called when a drag starts on the handle.
onPointerMove(event: PointerEvent<HTMLDivElement>) => void—Called as the pointer moves during a drag.
onPointerUp(event: PointerEvent<HTMLDivElement>) => void—Called when the drag ends and the drawer settles on a snap point.
onPointerCancel(event: PointerEvent<HTMLDivElement>) => void—Called when the browser cancels the drag.

Keyboard

KeyAction
Enter / SpaceOpen the dialog from its trigger or activate Close
EscapeRequest dismissal unless dismiss is none
Tab / Shift+TabMove within the modal dialog

Accessibility

DrawerPanel uses a dialog with target ids, so opening, dismissal, focus containment and focus return work before hydration; dismiss controls backdrop and Escape. Panels come in sm, md, lg and full widths and become bottom sheets on phones. Swipe starts on the handle or header, so the body still scrolls. The client API adds controlled state and snap points.

Styling hooks

data-uiify-drawerdata-partdata-sidedata-sizedata-backdropdata-statedata-dragging--uiify-drawer-inline-size--uiify-drawer-transform--uiify-sheet-offset