Popup
משטח קופץ המעוגן למפעיל שלו.
- דפדפנים
- Chrome 114+Firefox 125+Safari 17+
- שכבה
- 0
- גודל חבילה דחוסה
- 883 B
- מגבלת פריסה כפויה
- 0 ms
- מגבלת Axe
- 0
- תואם SSR
- כן
- מבוסס על
- elements/popover
- חוזה מפורסם
- סביבת בדיקות
מגרש ניסויים
import { PopupClose, PopupContent, PopupTrigger } from "@gunkin/uiify";
export default function Example() {
return (
<div data-part="root" data-uiify-popup="">
<PopupTrigger className="" target="actions-popover">
Actions
</PopupTrigger>
<PopupContent className="" id="actions-popover" mode="auto" side="bottom" align="center">
<a href="/profile">Profile</a>
<PopupClose className="" target="actions-popover">
Close
</PopupClose>
</PopupContent>
</div>
);
}/* Popup, popover, and tooltip surfaces. */
@layer components {
:where(
[data-uiify-popover][data-part="surface"],
[data-uiify-popup][data-part="content"],
[data-uiify-hover-card][data-part="content"]
):where(:not([popover]), :popover-open) {
display: flex;
}
:where(
[data-uiify-popover][data-part="surface"],
[data-uiify-popup][data-part="content"],
[data-uiify-hover-card][data-part="content"]
) {
flex-direction: column;
gap: var(--space-sm);
inline-size: max-content;
max-inline-size: 18rem;
padding: var(--space-md);
border: var(--border-width) solid var(--border);
border-radius: var(--radius-lg);
background-color: var(--popover);
color: var(--popover-foreground);
box-shadow: var(--shadow-popover);
}
:where(
[data-uiify-popover][data-part="surface"],
[data-uiify-popup][data-part="content"],
[data-uiify-hover-card][data-part="content"]
)[data-state="closed"] {
display: none;
}
[data-uiify-tooltip]:where(:not([popover]), :popover-open) {
display: block;
}
[data-uiify-tooltip] {
inline-size: max-content;
max-inline-size: 16rem;
padding-block: var(--space-xs);
padding-inline: var(--space-sm);
/* Cancels the UA popover default (`border: solid`, currentColor) — this
surface is borderless by design. */
border: none;
border-radius: var(--radius-sm);
background-color: var(--foreground);
color: var(--background);
font-size: var(--text-xs);
line-height: var(--leading-normal);
box-shadow: var(--shadow-popover);
}
:where([data-uiify-tooltip])[data-state="closed"] {
display: none;
}
@media (prefers-reduced-motion: no-preference) {
:where(
[data-uiify-popover][data-part="surface"],
[data-uiify-popup][data-part="content"],
[data-uiify-hover-card][data-part="content"],
[data-uiify-tooltip]
) {
transition: var(--transition-presence);
}
:where(
[data-uiify-popover][data-part="surface"],
[data-uiify-popup][data-part="content"],
[data-uiify-hover-card][data-part="content"],
[data-uiify-tooltip]
)[popover]:not(:popover-open) {
opacity: 0;
scale: var(--presence-scale);
}
@starting-style {
:where(
[data-uiify-popover][data-part="surface"],
[data-uiify-popup][data-part="content"],
[data-uiify-hover-card][data-part="content"],
[data-uiify-tooltip]
):popover-open {
opacity: 0;
scale: var(--presence-scale);
}
}
}
}import { PopupClose, PopupContent, PopupTrigger } from "@gunkin/uiify";
export default function Example() {
return (
<div data-part="root" data-uiify-popup="">
<PopupTrigger
className={
"relative isolate inline-flex items-center justify-center gap-1.5 min-h-10 min-w-10 px-5 py-px border-[len" +
"gth:var(--border-width)] border-solid border-transparent rounded-full bg-clip-padding text-base font-medi" +
"um leading-6 no-underline cursor-pointer [transition:var(--transition-colors)] focus-visible:[outline:non" +
"e] focus-visible:[box-shadow:0_0_0_var(--ring-width)_color-mix(in_oklch,_var(--ring)_20%,_transparent)] d" +
"isabled:opacity-50 disabled:cursor-not-allowed data-[disabled]:opacity-50 data-[disabled]:cursor-not-allo" +
"wed [&:is([data-selected],[aria-pressed=true],[aria-current=page])]:[--uiify-button-rim:rgb(255_255_255_/" +
"_20%)] [&:is([data-selected],[aria-pressed=true],[aria-current=page])]:[--uiify-button-wash:rgb(255_255_2" +
"55_/_15%)] [&:is([data-selected],[aria-pressed=true],[aria-current=page])]:border-transparent [&:is([data" +
"-selected],[aria-pressed=true],[aria-current=page])]:bg-primary [&:is([data-selected],[aria-pressed=true]" +
",[aria-current=page])]:text-primary-foreground [:checked+&]:[--uiify-button-rim:rgb(255_255_255_/_20%)] [" +
":checked+&]:[--uiify-button-wash:rgb(255_255_255_/_15%)] [:checked+&]:border-transparent [:checked+&]:bg-" +
"primary [:checked+&]:text-primary-foreground [@media_(any-hover:_hover)_and_(any-pointer:_fine)]:[&:is([d" +
"ata-selected],[aria-pressed=true],[aria-current=page]):hover:not(:disabled,[data-disabled])]:[background-" +
"color:color-mix(in_oklch,_var(--primary)_88%,_var(--primary-foreground))] [@media_(any-hover:_hover)_and_" +
"(any-pointer:_fine)]:[:checked:not(:disabled)+&:hover]:[background-color:color-mix(in_oklch,_var(--primar" +
"y)_88%,_var(--primary-foreground))] bg-foreground text-background [@media_(any-hover:_hover)_and_(any-poi" +
"nter:_fine)]:hover:[&:not(:disabled,[data-disabled])]:[background-color:color-mix(in_oklch,_var(--foregro" +
"und)_90%,_var(--background))] active:[&:not(:disabled,[data-disabled])]:[background-color:color-mix(in_ok" +
"lch,_var(--foreground)_80%,_var(--background))]"
}
target="actions-popover"
>
Actions
</PopupTrigger>
<PopupContent
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] flex-col gap-sm w-max max-w-72 p-md
border-[length:var(--border-width)] border-solid border-border rounded-lg bg-popover text-popover-foreground
shadow-popover [&:where(:not([popover]),:popover-open)]:flex data-[state=closed]:hidden
[&[data-positioning=native]]:[--uiify-anchor-offset:var(--space-sm)]
motion-safe:[transition:var(--transition-presence)] motion-safe:[&:not(:popover-open)]:opacity-0
motion-safe:[&:not(:popover-open)]:[scale:var(--presence-scale)]
motion-safe:starting:[&:popover-open]:opacity-0
motion-safe:starting:[&:popover-open]:[scale:var(--presence-scale)]
"
id="actions-popover"
mode="auto"
side="bottom"
align="center"
>
<a href="/profile">Profile</a>
<PopupClose
className={
"relative isolate inline-flex items-center justify-center gap-1.5 min-h-10 min-w-10 px-5 py-px border-[l" +
"ength:var(--border-width)] border-solid border-transparent rounded-full bg-clip-padding text-base font-" +
"medium leading-6 no-underline cursor-pointer [transition:var(--transition-colors)] focus-visible:[outli" +
"ne:none] focus-visible:[box-shadow:0_0_0_var(--ring-width)_color-mix(in_oklch,_var(--ring)_20%,_transpa" +
"rent)] disabled:opacity-50 disabled:cursor-not-allowed data-[disabled]:opacity-50 data-[disabled]:curso" +
"r-not-allowed [&:is([data-selected],[aria-pressed=true],[aria-current=page])]:[--uiify-button-rim:rgb(2" +
"55_255_255_/_20%)] [&:is([data-selected],[aria-pressed=true],[aria-current=page])]:[--uiify-button-wash" +
":rgb(255_255_255_/_15%)] [&:is([data-selected],[aria-pressed=true],[aria-current=page])]:border-transpa" +
"rent [&:is([data-selected],[aria-pressed=true],[aria-current=page])]:bg-primary [&:is([data-selected],[" +
"aria-pressed=true],[aria-current=page])]:text-primary-foreground [:checked+&]:[--uiify-button-rim:rgb(2" +
"55_255_255_/_20%)] [:checked+&]:[--uiify-button-wash:rgb(255_255_255_/_15%)] [:checked+&]:border-transp" +
"arent [:checked+&]:bg-primary [:checked+&]:text-primary-foreground [@media_(any-hover:_hover)_and_(any-" +
"pointer:_fine)]:[&:is([data-selected],[aria-pressed=true],[aria-current=page]):hover:not(:disabled,[dat" +
"a-disabled])]:[background-color:color-mix(in_oklch,_var(--primary)_88%,_var(--primary-foreground))] [@m" +
"edia_(any-hover:_hover)_and_(any-pointer:_fine)]:[:checked:not(:disabled)+&:hover]:[background-color:co" +
"lor-mix(in_oklch,_var(--primary)_88%,_var(--primary-foreground))] bg-transparent text-foreground before" +
":content-none after:content-none hover:[&:not(:disabled,[data-disabled])]:[background-color:color-mix(i" +
"n_oklch,_var(--foreground)_10%,_transparent)] active:[&:not(:disabled,[data-disabled])]:[background-col" +
"or:color-mix(in_oklch,_var(--foreground)_16%,_transparent)]"
}
target="actions-popover"
>
Close
</PopupClose>
</PopupContent>
</div>
);
}API
PopupTrigger
| מאפיין | טיפוס | ברירת מחדל | תיאור |
|---|---|---|---|
target* | string | — | מזהה ה-PopupContent שכפתור זה מחליף את מצב פתיחתו; הדפדפן מטפל בהחלפת המצב, בסגירה בלחיצה מחוץ לחלונית וב-Escape ללא הידרציה. |
children | ReactNode | — | תוכן כפתור הפתיחה. |
as | TAs & NativeButtonAs<TAs> | "button" | רכיב המעביר מאפיינים ו-ref לכפתור מובנה; תגיות אחרות נדחות, כי פקודות הפעלה דורשות כפתור אמיתי. |
PopupContent
| מאפיין | טיפוס | ברירת מחדל | תיאור |
|---|---|---|---|
id* | string | — | מזהה ייחודי שמספק המשתמש בספרייה; חלקי הפתיחה והסגירה מפנים אליו. |
side | "top" | "right" | "bottom" | "left" | "bottom" | הצד של כפתור הפתיחה שאליו המשטח מעוגן. |
align | "start" | "center" | "end" | "center" | יישור המשטח לאורך הצד שנבחר. |
mode | "auto" | "manual" | "auto" | התנהגות החלונית הקופצת: "auto" נסגרת בלחיצה מחוץ לה וב-Escape, ו-"manual" נשארת פתוחה עד שכפתור סגירה מסתיר אותה. |
children | ReactNode | — | תוכן המשטח של החלונית הקופצת. |
PopupClose
| מאפיין | טיפוס | ברירת מחדל | תיאור |
|---|---|---|---|
target* | string | — | מזהה ה-PopupContent שכפתור זה מסתיר. |
children | ReactNode | — | תוכן כפתור הסגירה. |
as | TAs & NativeButtonAs<TAs> | "button" | רכיב המעביר מאפיינים ו-ref לכפתור מובנה; תגיות אחרות נדחות, כי פקודות הפעלה דורשות כפתור אמיתי. |
Popup.Root (legacy compound)
| מאפיין | טיפוס | ברירת מחדל | תיאור |
|---|---|---|---|
id* | string | — | מזהה יציב למשטח החלונית הקופצת ולפקודות ההפעלה, המוזרק לילדים הישירים Trigger, Content ו-Close. |
mode | "auto" | "manual" | "hint" | "auto" | התנהגות החלונית הקופצת המועברת למשטח Content. |
className | string | — | המחלקה המוחלת על האלמנט העוטף. |
children | ReactNode | — | החלקים Trigger, Content ו-Close. |
Popup.Trigger (legacy compound)
| מאפיין | טיפוס | ברירת מחדל | תיאור |
|---|---|---|---|
className | string | — | המחלקה המוחלת על כפתור הפתיחה. |
children | ReactNode | — | תוכן כפתור הפתיחה. |
Popup.Content (legacy compound)
| מאפיין | טיפוס | ברירת מחדל | תיאור |
|---|---|---|---|
side | "top" | "right" | "bottom" | "left" | "bottom" | הצד של כפתור הפתיחה שאליו המשטח מעוגן. |
align | "start" | "center" | "end" | "center" | יישור המשטח לאורך הצד שנבחר. |
className | string | — | המחלקה המוחלת על משטח החלונית הקופצת. |
children | ReactNode | — | תוכן המשטח של החלונית הקופצת. |
Popup.Close (legacy compound)
| מאפיין | טיפוס | ברירת מחדל | תיאור |
|---|---|---|---|
className | string | — | המחלקה המוחלת על כפתור הסגירה. |
children | ReactNode | — | תוכן כפתור הסגירה. |
מקלדת
| מקש | פעולה |
|---|---|
| Escape | סגירה |
| Tab | מעבר אל תוכן החלונית הקופצת כשהיא פתוחה |
נגישות
Popover API המובנה: מפעיל popovertarget פותח וסוגר את המשטח לפני הרצת JavaScript כלשהו; הדפדפן אחראי לסגירה בלחיצה בחוץ, ל-Escape ולקינון, ומעגן את המשטח למפעיל שפתח אותו.
נקודות חיבור לעיצוב
data-sidedata-aligndata-positioningdata-uiify-popupdata-part="trigger|content|close"--uiify-trigger-open (inside [data-uiify-popup][data-part="root"])