דילוג לתוכן
uiify

Context menu

תפריט שנפתח בלחיצה ימנית.

דפדפנים
Chrome 151+
למה הגרסה הזאת?

CSS anchor positioning places this surface beside its trigger using position-anchor, and anchor(). Older Chrome versions may place the surface away from its trigger.

Firefox 151+
למה הגרסה הזאת?

CSS anchor positioning places this surface beside its trigger using position-anchor, and anchor(). Older Firefox versions may place the surface away from its trigger.

Safari 27+
למה הגרסה הזאת?

CSS anchor positioning places this surface beside its trigger using position-anchor, and anchor(). Older Safari versions may place the surface away from its trigger.

שכבה
2
גודל חבילה דחוסה
4.98 kB
מגבלת פריסה כפויה
0 ms
מגבלת Axe
0
תואם SSR
כן
חוזה מפורסם
סביבת בדיקות

מגרש ניסויים

Context Menu

סגור

אזור ללחיצה ימנית

פתוח

אזור ללחיצה ימנית
אזור לחיצה ימנית
import { ContextMenu } from "@gunkin/uiify";

export default function Example() {
  return (
    <ContextMenu.Root>
      <ContextMenu.Trigger className="">Right-click here</ContextMenu.Trigger>
      <ContextMenu.Content className="">
        <ContextMenu.Item className="">Copy</ContextMenu.Item>
        <ContextMenu.Separator className="" />
        <ContextMenu.Item className="">Paste</ContextMenu.Item>
      </ContextMenu.Content>
    </ContextMenu.Root>
  );
}
/* Generic skin for custom core surfaces used by the demo and consumers. */

@layer components {
  [data-uiify-surface] {
    display: grid;
    gap: var(--space-md);
    inline-size: max-content;
    max-inline-size: min(28rem, calc(100vw - 2 * var(--space-lg)));
    padding: var(--space-lg);
    border: var(--border-width) solid var(--border);
    border-radius: var(--radius-xl);
    background-color: var(--card);
    color: var(--card-foreground);
    box-shadow: var(--shadow-popover);
  }

  [data-uiify-surface][popover]:not(:popover-open) {
    display: none;
  }

  @media (prefers-reduced-motion: no-preference) {
    [data-uiify-surface][popover] {
      transition: var(--transition-presence);
    }

    [data-uiify-surface][popover]:not(:popover-open) {
      opacity: 0;
      scale: var(--presence-scale);
    }

    @starting-style {
      [data-uiify-surface][popover]:popover-open {
        opacity: 0;
        scale: var(--presence-scale);
      }
    }
  }
}

/* Dropdown menu — a compact command surface with explicit anatomy hooks. */

@layer components {
  [data-uiify-menu-bar] {
    display: inline-flex;
    align-items: center;
    gap: var(--space-xs);
    padding: var(--space-xs);
    border: var(--border-width) solid var(--border);
    border-radius: var(--radius-lg);
    background-color: var(--background);
  }

  :where(
    [data-uiify-menu] :is([data-part="content"], [data-part="sub-content"]),
    [data-uiify-menu]:is([data-part="content"], [data-part="sub-content"])
  ):where(:not([popover]), :popover-open) {
    display: flex;
  }

  :where(
    [data-uiify-menu] :is([data-part="content"], [data-part="sub-content"]),
    [data-uiify-menu]:is([data-part="content"], [data-part="sub-content"])
  ) {
    flex-direction: column;
    min-inline-size: 12rem;
    max-block-size: min(24rem, calc(100dvb - 2rem));
    overflow-block: auto;
    overscroll-behavior: contain;
    padding: var(--space-xs);
    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);
    transform-origin: var(--transform-origin, top);
  }

  :where(
    [data-uiify-menu] :is([data-part="content"], [data-part="sub-content"]),
    [data-uiify-menu]:is([data-part="content"], [data-part="sub-content"])
  )[data-state="closed"] {
    display: none;
  }

  [data-uiify-menu]
    :is(
      [data-part="item"],
      [data-part="checkbox-item"],
      [data-part="radio-item"],
      [data-part="sub-trigger"]
    ) {
    display: flex;
    align-items: center;
    column-gap: var(--space-md);
    padding-block: var(--space-sm);
    padding-inline: var(--space-md);
    border-radius: calc(var(--radius-lg) - var(--space-xs));
    cursor: pointer;
    user-select: none;
    inline-size: 100%;
    border: 0;
    background: transparent;
    color: inherit;
    font: inherit;
    font-size: var(--text-sm) !important;
    line-height: var(--leading-normal);
    text-align: start;
    appearance: none;
  }

  [data-uiify-menu]
    :is(
      [data-part="item"],
      [data-part="checkbox-item"],
      [data-part="radio-item"],
      [data-part="sub-trigger"]
    ):is(:hover, :focus-visible, [data-highlighted]) {
    background-color: var(--accent);
    color: var(--accent-foreground);
    outline: none;
  }

  [data-uiify-menu]
    [data-part="radio-item"]:hover[role="menuitemradio"][data-state="checked"]
    [data-part="item-indicator"],
  [data-uiify-menu]
    [data-part="radio-item"]:focus-visible[role="menuitemradio"][data-state="checked"]
    [data-part="item-indicator"],
  [data-uiify-menu]
    [data-part="radio-item"][data-highlighted][role="menuitemradio"][data-state="checked"]
    [data-part="item-indicator"] {
    border-color: var(--accent-foreground);
  }

  [data-uiify-menu]
    :is(
      [data-part="item"],
      [data-part="checkbox-item"],
      [data-part="radio-item"],
      [data-part="sub-trigger"]
    ):is([aria-disabled="true"], [data-disabled]) {
    opacity: 0.5;
    pointer-events: none;
  }

  [data-uiify-menu]
    :is(
      [data-part="item"],
      [data-part="checkbox-item"],
      [data-part="radio-item"],
      [data-part="sub-trigger"]
    )[data-danger] {
    color: var(--destructive, var(--foreground));
  }

  [data-uiify-menu]
    :is(
      [data-part="item"],
      [data-part="checkbox-item"],
      [data-part="radio-item"],
      [data-part="sub-trigger"]
    )[data-danger]:is(:hover, :focus-visible, [data-highlighted]) {
    background-color: var(--destructive);
    color: var(--destructive-foreground);
  }

  [data-uiify-menu] [data-part="item-icon"],
  [data-uiify-menu] [data-part="item-indicator"] {
    display: inline-grid;
    place-items: center;
    inline-size: 1.25rem;
    block-size: 1.25rem;
    flex: 0 0 1.25rem;
  }

  [data-uiify-menu] [data-part="item-indicator"] {
    border: var(--border-width) solid var(--input);
    border-radius: var(--radius-xs);
    color: transparent;
  }

  [role="menuitemcheckbox"][data-state="checked"] [data-part="item-indicator"],
  [role="menuitemcheckbox"][data-state="indeterminate"] [data-part="item-indicator"] {
    border-color: var(--primary);
    background: var(--primary);
    color: var(--primary-foreground);
  }

  [role="menuitemcheckbox"][data-state="checked"] [data-part="item-indicator"]::before {
    inline-size: 0.65rem;
    block-size: 0.65rem;
    background-color: currentcolor;
    clip-path: polygon(14% 44%, 0 65%, 38% 100%, 100% 22%, 84% 6%, 38% 68%);
    content: "";
  }

  [role="menuitemcheckbox"][data-state="indeterminate"] [data-part="item-indicator"]::before {
    inline-size: 0.65rem;
    block-size: 0.12rem;
    background: currentcolor;
    content: "";
  }

  [role="menuitemradio"] [data-part="item-indicator"] {
    border-radius: 50%;
  }

  [role="menuitemradio"][data-state="checked"] [data-part="item-indicator"] {
    border-width: 5px;
    border-color: var(--primary);
    background: var(--card);
  }

  [role="menuitemradio"][data-state="checked"] [data-part="item-indicator"]::before {
    content: none;
  }

  [data-uiify-menu] [data-part="item-icon"] > svg,
  [data-uiify-menu] [data-part="item-indicator"] > svg {
    display: block;
    inline-size: 100%;
    block-size: 100%;
  }

  [data-uiify-menu] [data-part="item-text"] {
    display: grid;
    flex: 1 1 auto;
    min-inline-size: 0;
  }

  [data-uiify-menu] [data-part="item-description"] {
    color: var(--muted-foreground);
    font-size: var(--text-xs);
    line-height: var(--leading-normal);
  }

  [data-uiify-menu]
    :is(
      [data-part="item"],
      [data-part="checkbox-item"],
      [data-part="radio-item"],
      [data-part="sub-trigger"]
    ):is(:hover, :focus-visible, [data-highlighted])
    [data-part="item-description"] {
    color: inherit;
    opacity: 0.8;
  }

  [data-uiify-menu] [data-part="shortcut"] {
    margin-inline-start: auto;
    color: var(--muted-foreground);
    font-size: var(--text-xs);
    font-family: inherit;
    font-weight: inherit;
    line-height: 1;
    white-space: nowrap;
  }

  [data-uiify-menu]
    :is(
      [data-part="item"],
      [data-part="checkbox-item"],
      [data-part="radio-item"],
      [data-part="sub-trigger"]
    ):is(:hover, :focus-visible, [data-highlighted])
    [data-part="shortcut"] {
    color: inherit;
    opacity: 0.85;
  }

  [data-uiify-menu] [data-part="label"] {
    padding-block: var(--space-xs);
    padding-inline: var(--space-md);
    color: var(--muted-foreground);
    font-size: var(--text-xs);
    font-weight: var(--weight-semibold);
  }

  [data-uiify-menu] [data-part="separator"] {
    block-size: var(--border-width);
    margin-block: var(--space-xs);
    margin-inline: calc(-1 * var(--space-xs));
    background-color: var(--border);
  }

  [data-uiify-menu] [data-part="sub-content"] {
    min-inline-size: 11rem;
  }

  [data-uiify-menu] [data-part="sub-content"][data-side="right"] {
    --uiify-anchor-offset: 0;

    inset-block-start: calc(anchor(start) - var(--space-xs));
  }

  @media (prefers-reduced-motion: no-preference) {
    :where(
      [data-uiify-menu] :is([data-part="content"], [data-part="sub-content"]),
      [data-uiify-menu]:is([data-part="content"], [data-part="sub-content"])
    ) {
      transition: var(--transition-presence);
    }

    :where(
        [data-uiify-menu] :is([data-part="content"], [data-part="sub-content"]),
        [data-uiify-menu]:is([data-part="content"], [data-part="sub-content"])
      )[popover]:not(:popover-open) {
      opacity: 0;
      scale: var(--presence-scale);
    }

    @starting-style {
      :where(
        [data-uiify-menu] :is([data-part="content"], [data-part="sub-content"]),
        [data-uiify-menu]:is([data-part="content"], [data-part="sub-content"])
      ):popover-open {
        opacity: 0;
        scale: var(--presence-scale);
      }
    }
  }
}

@layer components {
  :is([data-uiify-dropdown-menu], [data-uiify-context-menu])
    [role="menuitemradio"]
    [data-part="item-indicator"] {
    border-radius: 50%;
  }
}
import { ContextMenu } from "@gunkin/uiify";

export default function Example() {
  return (
    <ContextMenu.Root>
      <ContextMenu.Trigger
        className="
          grid gap-md w-max max-w-[min(28rem,calc(100vw_-_2_*_var(--space-lg)))] p-6 border border-border rounded-xl
          bg-card text-card-foreground shadow-popover [&[popover]:not(:popover-open)]:hidden
          motion-safe:[&[popover]]:[transition:var(--transition-presence)]
          motion-safe:[&[popover]:not(:popover-open)]:opacity-0
          motion-safe:[&[popover]:not(:popover-open)]:[scale:var(--presence-scale)]
          motion-safe:starting:[&[popover]:popover-open]:opacity-0
          motion-safe:starting:[&[popover]:popover-open]:[scale:var(--presence-scale)]
        "
      >
        Right-click here
      </ContextMenu.Trigger>
      <ContextMenu.Content
        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 [min-inline-size:12rem]
          [max-block-size:min(24rem,calc(100dvb_-_2rem))] overflow-y-auto overscroll-contain p-xs
          border-[length:var(--border-width)] border-solid border-border rounded-lg bg-popover text-popover-foreground
          shadow-popover [transform-origin:var(--transform-origin,top)] data-[state=closed]:hidden
          [&:where(:not([popover]),:popover-open)]:flex [&[data-part=sub-content]]:[min-inline-size:11rem]
          [&[data-part=sub-content][data-side=right]]:[--uiify-anchor-offset:0]
          [&[data-part=sub-content][data-side=right]]:[inset-block-start:calc(anchor(start)_-_var(--space-xs))]
          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)]
        "
      >
        <ContextMenu.Item
          className="
            flex items-center gap-md w-full py-sm px-md border-0 rounded-[calc(var(--radius-lg)_-_var(--space-xs))]
            bg-transparent text-inherit [font-family:inherit] [font-weight:inherit] text-sm
            [line-height:var(--leading-normal)] text-start cursor-pointer select-none appearance-none hover:bg-accent
            hover:text-accent-foreground focus-visible:bg-accent focus-visible:text-accent-foreground
            focus-visible:outline-none data-[highlighted]:bg-accent data-[highlighted]:text-accent-foreground
            aria-[disabled=true]:opacity-50 aria-[disabled=true]:pointer-events-none data-[disabled]:opacity-50
            data-[disabled]:pointer-events-none data-[danger]:text-destructive data-[danger]:hover:bg-destructive
            data-[danger]:hover:text-destructive-foreground data-[danger]:focus-visible:bg-destructive
            data-[danger]:focus-visible:text-destructive-foreground data-[danger]:data-[highlighted]:bg-destructive
            data-[danger]:data-[highlighted]:text-destructive-foreground
          "
        >
          Copy
        </ContextMenu.Item>
        <ContextMenu.Separator
          className="
            [block-size:var(--border-width)] [margin-block:var(--space-xs)] [margin-inline:calc(-1_*var(--space-xs))]
            bg-border
          "
        />
        <ContextMenu.Item
          className="
            flex items-center gap-md w-full py-sm px-md border-0 rounded-[calc(var(--radius-lg)_-_var(--space-xs))]
            bg-transparent text-inherit [font-family:inherit] [font-weight:inherit] text-sm
            [line-height:var(--leading-normal)] text-start cursor-pointer select-none appearance-none hover:bg-accent
            hover:text-accent-foreground focus-visible:bg-accent focus-visible:text-accent-foreground
            focus-visible:outline-none data-[highlighted]:bg-accent data-[highlighted]:text-accent-foreground
            aria-[disabled=true]:opacity-50 aria-[disabled=true]:pointer-events-none data-[disabled]:opacity-50
            data-[disabled]:pointer-events-none data-[danger]:text-destructive data-[danger]:hover:bg-destructive
            data-[danger]:hover:text-destructive-foreground data-[danger]:focus-visible:bg-destructive
            data-[danger]:focus-visible:text-destructive-foreground data-[danger]:data-[highlighted]:bg-destructive
            data-[danger]:data-[highlighted]:text-destructive-foreground
          "
        >
          Paste
        </ContextMenu.Item>
      </ContextMenu.Content>
    </ContextMenu.Root>
  );
}

API

ContextMenu.Root

מאפייןטיפוסברירת מחדלתיאור
childrenReactNode—אזור הפתיחה ותוכן התפריט.
defaultOpenboolean—מצב הפתיחה ההתחלתי של התפריט כשאינו מבוקר.
idstring—המזהה המשמש לאלמנט החלונית הקופצת המכיל את התפריט.
slotPropsContextMenuRootSlotProps—מאפיינים מובנים לעוגן הווירטואלי שנוצר; סגנונות המיקום וסמני הנגישות נשארים בשליטת התפריט.
onOpenChangePopoverChangeHandler—נקראת כשהתפריט נפתח או נסגר, עם הסיבה והאירוע שגרם לכך.
openboolean—מצב הפתיחה של התפריט, ההופך אותו למבוקר.

ContextMenu.Trigger

מאפייןטיפוסברירת מחדלתיאור
childrenReactNode—אזור שפותח את התפריט בלחיצה ימנית.
classNamestring—המחלקה המוחלת על האלמנט המוצג.
renderReactElement | ((props, state) => ReactElement)—החלפת האלמנט המוצג תוך שימור ההתנהגות וקישורי הנגישות.

ContextMenu.Content

מאפייןטיפוסברירת מחדלתיאור
childrenReactNode—הפריטים, התוויות והמפרידים של התפריט.
classNamestring—המחלקה המוחלת על האלמנט המוצג.
renderReactElement | ((props, state) => ReactElement)—החלפת האלמנט המוצג תוך שימור ההתנהגות וקישורי הנגישות.

ContextMenu.Item

מאפייןטיפוסברירת מחדלתיאור
childrenReactNode—תוכן הפריט.
classNamestring—המחלקה המוחלת על האלמנט המוצג.
Native div props, styles, events, and refComponentPropsWithRef<"div">—המאפיינים, הסגנונות, האירועים וה-ref של האלמנט המובנה מועברים הלאה.
disabledbooleanfalseמשבית את הפריט ומדלג עליו בניווט במקלדת.
onSelect(event: MenuSelectEvent) => void—נקראת כשהפריט נבחר; קריאה ל-preventDefault על האירוע משאירה את התפריט פתוח.
textValuestring—הטקסט המשמש להתאמה בעת חיפוש בהקלדה כשתוכן הפריט אינו טקסט פשוט.
renderReactElement | ((props, state) => ReactElement)—החלפת האלמנט המוצג תוך שימור ההתנהגות וקישורי הנגישות.

ContextMenu.CheckboxItem

מאפייןטיפוסברירת מחדלתיאור
checkedboolean | "indeterminate"falseמצב הסימון של הפריט.
childrenReactNode—תוכן הפריט.
classNamestring—המחלקה המוחלת על האלמנט המוצג.
Native div props, styles, events, and refComponentPropsWithRef<"div">—המאפיינים, הסגנונות, האירועים וה-ref של האלמנט המובנה מועברים הלאה.
disabledbooleanfalseמשבית את הפריט ומדלג עליו בניווט במקלדת.
onCheckedChange(checked: boolean) => void—נקראת עם מצב הסימון החדש כשהפריט נבחר.
textValuestring—הטקסט המשמש להתאמה בעת חיפוש בהקלדה כשתוכן הפריט אינו טקסט פשוט.

ContextMenu.RadioItem

מאפייןטיפוסברירת מחדלתיאור
value*string—הערך שפריט זה בוחר בתפריט.
childrenReactNode—תוכן הפריט.
classNamestring—המחלקה המוחלת על האלמנט המוצג.
Native div props, styles, events, and refComponentPropsWithRef<"div">—המאפיינים, הסגנונות, האירועים וה-ref של האלמנט המובנה מועברים הלאה.
disabledbooleanfalseמשבית את הפריט ומדלג עליו בניווט במקלדת.
textValuestring—הטקסט המשמש להתאמה בעת חיפוש בהקלדה כשתוכן הפריט אינו טקסט פשוט.

ContextMenu.Label

מאפייןטיפוסברירת מחדלתיאור
childrenReactNode—טקסט כותרת הקבוצה.
classNamestring—המחלקה המוחלת על האלמנט המוצג.
Native div props, styles, events, and refComponentPropsWithRef<"div">—המאפיינים, הסגנונות, האירועים וה-ref של האלמנט המובנה מועברים הלאה.

ContextMenu.Separator

מאפייןטיפוסברירת מחדלתיאור
classNamestring—המחלקה המוחלת על האלמנט המוצג.
Native div props, styles, events, and refComponentPropsWithRef<"div">—המאפיינים, הסגנונות, האירועים וה-ref של האלמנט המובנה מועברים הלאה.

ContextMenu.Sub

מאפייןטיפוסברירת מחדלתיאור
childrenReactNode—כפתור הפתיחה של תפריט המשנה ותוכנו.

ContextMenu.Sub.Trigger

מאפייןטיפוסברירת מחדלתיאור
childrenReactNode—תווית כפתור הפתיחה של תפריט המשנה.
classNamestring—המחלקה המוחלת על האלמנט המוצג.
Native div props, styles, events, and refComponentPropsWithRef<"div">—המאפיינים, הסגנונות, האירועים וה-ref של האלמנט המובנה מועברים הלאה.
disabledbooleanfalseמשבית את כפתור הפתיחה ומדלג עליו בניווט במקלדת.
textValuestring—הטקסט המשמש להתאמה בעת חיפוש בהקלדה כשתוכן הפריט אינו טקסט פשוט.

ContextMenu.Sub.Content

מאפייןטיפוסברירת מחדלתיאור
childrenReactNode—הפריטים של תפריט המשנה.
classNamestring—המחלקה המוחלת על האלמנט המוצג.
Native div props, styles, events, and refComponentPropsWithRef<"div">—המאפיינים, הסגנונות, האירועים וה-ref של האלמנט המובנה מועברים הלאה.

מקלדת

מקשפעולה
Shift+F10 / Menu keyפתיחה ליד האלמנט הממוקד
↑ / ↓מעבר בין פריטים
Escapeסגירה והחזרת המיקוד

נגישות

דפוס תפריט שנפתח במיקום המצביע או במיקום שנקבע באמצעות המקלדת.

נקודות חיבור לעיצוב

data-statedata-highlighted
דף זה תורגם אוטומטית וטרם נבדק.