Drawer
从屏幕边缘滑入的面板。
- 浏览器
- Chrome 123+Firefox 121+Safari 17.5+
- 层级
- 0
- 压缩后大小
- 4.01 kB
- 强制布局预算
- 0 ms
- axe 预算
- 0
- 支持 SSR
- 是
- 基于
- elements/dialog
- 公开契约
- 测试环境
交互示例
Drawer
关闭
吸附点
宽度
方向
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
| 属性 | 类型 | 默认值 | 说明 |
|---|---|---|---|
size | "sm" | "md" | "lg" | "full" | "md" | 桌面宽度:24rem、32rem、40rem或可用宽度。在移动端,所有尺寸都变为纵向底部面板。 |
dismiss | "any" | "closerequest" | "none" | "any" | 原生关闭策略。Any允许点击遮罩、Escape和移动端向下滑动;none要求显式关闭控件。 |
backdrop | "opaque" | "transparent" | "opaque" | 遮罩外观;不改变模态语义。 |
footer | ReactNode | — | 可滚动主体之后的操作。 |
id* | string | — | 触发器和关闭按钮指向的唯一对话框id,让抽屉在水合前即可打开和关闭。 |
trigger* | ReactNode | — | 打开抽屉的按钮内容。 |
title* | ReactNode | — | 在抽屉内渲染的标题,用作无障碍名称。 |
description | ReactNode | — | 在标题下方渲染的辅助文本,由aria-describedby引用。 |
children | ReactNode | — | 位于描述和关闭按钮之间的主体内容。 |
side | "top" | "right" | "bottom" | "left" | "bottom" | 抽屉从哪条边缘滑入。 |
closeLabel | string | "Close" | 圆形关闭图标的无障碍标签。 |
className | string | — | 应用于dialog元素的类名。 |
Drawer.Root (client)
| 属性 | 类型 | 默认值 | 说明 |
|---|---|---|---|
open | boolean | — | 受控打开状态。 |
defaultOpen | boolean | — | 非受控的初始打开状态。 |
onOpenChange | DialogChangeHandler | — | 使用下一个打开状态及变更原因详情调用。 |
side | "top" | "right" | "bottom" | "left" | "bottom" | 抽屉从哪条边缘滑入,同时决定拖动轴。 |
modal | boolean | true | 通过showModal()打开,使页面其余部分在遮罩后处于inert状态。 |
dismissible | boolean | true | 允许拖过最后一个吸附点来关闭抽屉。 |
snapPoints | readonly number[] | — | 拖动后面板停靠的位置,以抽屉尺寸的比例表示。 |
activeSnapPoint | number | — | 受控吸附点,为snapPoints中的一个值。 |
defaultActiveSnapPoint | number | — | 非受控的初始吸附点。 |
onSnapChange | (snap: number) => void | — | 使用抽屉最终停靠的吸附点调用。 |
children | ReactNode | — | Trigger、Content和内部组成部分。 |
Drawer.Trigger (client)
| 属性 | 类型 | 默认值 | 说明 |
|---|---|---|---|
className | string | — | 应用于触发器按钮的类名。 |
onClick | (event: MouseEvent<HTMLButtonElement>) => void | — | 点击触发器后、抽屉打开前调用。 |
ref | Ref<HTMLButtonElement> | — | 触发器按钮的ref,抽屉关闭时会重新聚焦该按钮。 |
children | ReactNode | — | 触发器按钮的内容。 |
Drawer.Content (client)
| 属性 | 类型 | 默认值 | 说明 |
|---|---|---|---|
className | string | — | 应用于dialog元素的类名。 |
style | CSSProperties | — | 与抽屉应用的拖动transform合并的内联style。 |
onCancel | ReactEventHandler<HTMLDialogElement> | — | 原生dialog cancel事件发生时调用,例如按下Escape。 |
onClose | ReactEventHandler<HTMLDialogElement> | — | 原生dialog close事件发生时调用。 |
ref | Ref<HTMLDialogElement> | — | dialog元素的ref。 |
children | ReactNode | — | 抽屉内容。 |
Drawer.Title (client)
| 属性 | 类型 | 默认值 | 说明 |
|---|---|---|---|
className | string | — | 应用于标题元素的类名。 |
children | ReactNode | — | 标题内容,成为抽屉的无障碍名称。 |
Drawer.Description (client)
| 属性 | 类型 | 默认值 | 说明 |
|---|---|---|---|
className | string | — | 应用于描述元素的类名。 |
children | ReactNode | — | 描述内容,由aria-describedby引用。 |
Drawer.Close (client)
| 属性 | 类型 | 默认值 | 说明 |
|---|---|---|---|
className | string | — | 应用于关闭按钮的类名。 |
onClick | (event: MouseEvent<HTMLButtonElement>) => void | — | 点击关闭按钮后、抽屉关闭前调用。 |
children | ReactNode | — | 关闭按钮的内容。 |
Drawer.Handle (client)
| 属性 | 类型 | 默认值 | 说明 |
|---|---|---|---|
className | string | — | 应用于拖动手柄的类名。 |
onPointerDown | (event: PointerEvent<HTMLDivElement>) => void | — | 在手柄上开始拖动时调用。 |
onPointerMove | (event: PointerEvent<HTMLDivElement>) => void | — | 拖动期间指针移动时调用。 |
onPointerUp | (event: PointerEvent<HTMLDivElement>) => void | — | 拖动结束且抽屉停靠到吸附点时调用。 |
onPointerCancel | (event: PointerEvent<HTMLDivElement>) => void | — | 浏览器取消拖动时调用。 |
键盘
| 按键 | 操作 |
|---|---|
| Enter / Space | 通过触发器打开对话框,或激活Close |
| Escape | 请求关闭,除非dismiss为none |
| Tab / Shift+Tab | 在模态对话框内移动 |
无障碍
DrawerPanel使用带目标id的对话框,因此打开、关闭、焦点限制和焦点返回在水合前就能工作;dismiss控制遮罩和Escape行为。面板有sm、md、lg和full宽度,在手机上变为底部面板。滑动从手柄或页头开始,因此主体仍可滚动。客户端API添加受控状态和吸附点。
样式钩子
data-uiify-drawerdata-partdata-sidedata-sizedata-backdropdata-statedata-dragging--uiify-drawer-inline-size--uiify-drawer-transform--uiify-sheet-offset