דילוג לתוכן
uiify

Popup

משטח קופץ המעוגן למפעיל שלו.

דפדפנים
Chrome 114+Firefox 125+Safari 17+
שכבה
0
גודל חבילה דחוסה
883 B
מגבלת פריסה כפויה
0 ms
מגבלת Axe
0
תואם SSR
כן
מבוסס על
elements/popover
חוזה מפורסם
סביבת בדיקות

מגרש ניסויים

Popup

Preferences

Invite teammate

Manual dismissal

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 ללא הידרציה.
childrenReactNode—תוכן כפתור הפתיחה.
asTAs & 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" נשארת פתוחה עד שכפתור סגירה מסתיר אותה.
childrenReactNode—תוכן המשטח של החלונית הקופצת.

PopupClose

מאפייןטיפוסברירת מחדלתיאור
target*string—מזהה ה-PopupContent שכפתור זה מסתיר.
childrenReactNode—תוכן כפתור הסגירה.
asTAs & NativeButtonAs<TAs>"button"רכיב המעביר מאפיינים ו-ref לכפתור מובנה; תגיות אחרות נדחות, כי פקודות הפעלה דורשות כפתור אמיתי.

Popup.Root (legacy compound)

מאפייןטיפוסברירת מחדלתיאור
id*string—מזהה יציב למשטח החלונית הקופצת ולפקודות ההפעלה, המוזרק לילדים הישירים Trigger, Content ו-Close.
mode"auto" | "manual" | "hint""auto"התנהגות החלונית הקופצת המועברת למשטח Content.
classNamestring—המחלקה המוחלת על האלמנט העוטף.
childrenReactNode—החלקים Trigger, Content ו-Close.

Popup.Trigger (legacy compound)

מאפייןטיפוסברירת מחדלתיאור
classNamestring—המחלקה המוחלת על כפתור הפתיחה.
childrenReactNode—תוכן כפתור הפתיחה.

Popup.Content (legacy compound)

מאפייןטיפוסברירת מחדלתיאור
side"top" | "right" | "bottom" | "left""bottom"הצד של כפתור הפתיחה שאליו המשטח מעוגן.
align"start" | "center" | "end""center"יישור המשטח לאורך הצד שנבחר.
classNamestring—המחלקה המוחלת על משטח החלונית הקופצת.
childrenReactNode—תוכן המשטח של החלונית הקופצת.

Popup.Close (legacy compound)

מאפייןטיפוסברירת מחדלתיאור
classNamestring—המחלקה המוחלת על כפתור הסגירה.
childrenReactNode—תוכן כפתור הסגירה.

מקלדת

מקשפעולה
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"])
דף זה תורגם אוטומטית וטרם נבדק.