Context menu
Меню, которое открывается щелчком правой кнопки мыши.
- Браузеры
- Chrome 151+Firefox 151+Safari 27+
- Уровень
- 2
- Сжатый размер
- 4.90 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);
corner-shape: squircle;
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);
corner-shape: squircle;
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);
corner-shape: squircle;
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));
corner-shape: squircle;
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);
corner-shape: squircle;
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%;
corner-shape: round;
}
}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
[corner-shape:squircle] 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 [corner-shape:squircle] 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))]" +
" [corner-shape:squircle] bg-transparent text-inherit [font-family:inherit] [font-weight:inherit] text-s" +
"m [line-height:var(--leading-normal)] text-start cursor-pointer select-none appearance-none hover:bg-ac" +
"cent hover:text-accent-foreground focus-visible:bg-accent focus-visible:text-accent-foreground focus-vi" +
"sible:outline-none data-[highlighted]:bg-accent data-[highlighted]:text-accent-foreground aria-[disable" +
"d=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]:hov" +
"er:text-destructive-foreground data-[danger]:focus-visible:bg-destructive data-[danger]:focus-visible:t" +
"ext-destructive-foreground data-[danger]:data-[highlighted]:bg-destructive data-[danger]:data-[highligh" +
"ted]:text-destructive-foreground [&_[data-part=item-icon]]:inline-grid [&_[data-part=item-icon]]:place-" +
"items-center [&_[data-part=item-icon]]:size-5 [&_[data-part=item-icon]]:flex-[0_0_1.25rem] [&_[data-par" +
"t=item-indicator]]:inline-grid [&_[data-part=item-indicator]]:place-items-center [&_[data-part=item-ind" +
"icator]]:size-5 [&_[data-part=item-indicator]]:flex-[0_0_1.25rem] [&_[data-part=item-indicator]>svg]:bl" +
"ock [&_[data-part=item-indicator]>svg]:size-full [&[role=menuitemcheckbox]_[data-part=item-indicator]]:" +
"border-[length:var(--border-width)] [&[role=menuitemcheckbox]_[data-part=item-indicator]]:border-input " +
"[&[role=menuitemcheckbox]_[data-part=item-indicator]]:rounded-xs [&[role=menuitemcheckbox][data-state=c" +
"hecked]_[data-part=item-indicator]]:border-primary [&[role=menuitemcheckbox][data-state=checked]_[data-" +
"part=item-indicator]]:bg-primary [&[role=menuitemcheckbox][data-state=checked]_[data-part=item-indicato" +
"r]]:text-primary-foreground [&[role=menuitemcheckbox][data-state=checked]_[data-part=item-indicator]::b" +
"efore]:content-[''] [&[role=menuitemcheckbox][data-state=checked]_[data-part=item-indicator]::before]:s" +
"ize-[0.65rem] [&[role=menuitemcheckbox][data-state=checked]_[data-part=item-indicator]::before]:bg-curr" +
"ent [&[role=menuitemcheckbox][data-state=checked]_[data-part=item-indicator]::before]:[clip-path:polygo" +
"n(14%_44%,0_65%,38%_100%,100%_22%,84%_6%,38%_68%)] [&[role=menuitemcheckbox][data-state=indeterminate]_" +
"[data-part=item-indicator]]:border-primary [&[role=menuitemcheckbox][data-state=indeterminate]_[data-pa" +
"rt=item-indicator]]:bg-primary [&[role=menuitemcheckbox][data-state=indeterminate]_[data-part=item-indi" +
"cator]]:text-primary-foreground [&[role=menuitemcheckbox][data-state=indeterminate]_[data-part=item-ind" +
"icator]::before]:content-[''] [&[role=menuitemcheckbox][data-state=indeterminate]_[data-part=item-indic" +
"ator]::before]:w-[0.65rem] [&[role=menuitemcheckbox][data-state=indeterminate]_[data-part=item-indicato" +
"r]::before]:h-[0.12rem] [&[role=menuitemcheckbox][data-state=indeterminate]_[data-part=item-indicator]:" +
":before]:bg-current [&[role=menuitemradio]_[data-part=item-indicator]]:rounded-full [&[role=menuitemrad" +
"io][data-state=checked]_[data-part=item-indicator]]:border-[5px] [&[role=menuitemradio][data-state=chec" +
"ked]_[data-part=item-indicator]]:border-primary [&[role=menuitemradio][data-state=checked]_[data-part=i" +
"tem-indicator]]:bg-card [&_[data-part=item-text]]:grid [&_[data-part=item-text]]:flex-auto [&_[data-par" +
"t=item-text]]:[min-inline-size:0] [&_[data-part=item-description]]:text-muted-foreground [&_[data-part=" +
"item-description]]:text-xs [&_[data-part=item-description]]:[line-height:var(--leading-normal)] [&_[dat" +
"a-part=shortcut]]:ms-auto [&_[data-part=shortcut]]:text-muted-foreground [&_[data-part=shortcut]]:text-" +
"xs [&_[data-part=shortcut]]:leading-none [&_[data-part=shortcut]]:whitespace-nowrap"
}
>
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))]" +
" [corner-shape:squircle] bg-transparent text-inherit [font-family:inherit] [font-weight:inherit] text-s" +
"m [line-height:var(--leading-normal)] text-start cursor-pointer select-none appearance-none hover:bg-ac" +
"cent hover:text-accent-foreground focus-visible:bg-accent focus-visible:text-accent-foreground focus-vi" +
"sible:outline-none data-[highlighted]:bg-accent data-[highlighted]:text-accent-foreground aria-[disable" +
"d=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]:hov" +
"er:text-destructive-foreground data-[danger]:focus-visible:bg-destructive data-[danger]:focus-visible:t" +
"ext-destructive-foreground data-[danger]:data-[highlighted]:bg-destructive data-[danger]:data-[highligh" +
"ted]:text-destructive-foreground [&_[data-part=item-icon]]:inline-grid [&_[data-part=item-icon]]:place-" +
"items-center [&_[data-part=item-icon]]:size-5 [&_[data-part=item-icon]]:flex-[0_0_1.25rem] [&_[data-par" +
"t=item-indicator]]:inline-grid [&_[data-part=item-indicator]]:place-items-center [&_[data-part=item-ind" +
"icator]]:size-5 [&_[data-part=item-indicator]]:flex-[0_0_1.25rem] [&_[data-part=item-indicator]>svg]:bl" +
"ock [&_[data-part=item-indicator]>svg]:size-full [&[role=menuitemcheckbox]_[data-part=item-indicator]]:" +
"border-[length:var(--border-width)] [&[role=menuitemcheckbox]_[data-part=item-indicator]]:border-input " +
"[&[role=menuitemcheckbox]_[data-part=item-indicator]]:rounded-xs [&[role=menuitemcheckbox][data-state=c" +
"hecked]_[data-part=item-indicator]]:border-primary [&[role=menuitemcheckbox][data-state=checked]_[data-" +
"part=item-indicator]]:bg-primary [&[role=menuitemcheckbox][data-state=checked]_[data-part=item-indicato" +
"r]]:text-primary-foreground [&[role=menuitemcheckbox][data-state=checked]_[data-part=item-indicator]::b" +
"efore]:content-[''] [&[role=menuitemcheckbox][data-state=checked]_[data-part=item-indicator]::before]:s" +
"ize-[0.65rem] [&[role=menuitemcheckbox][data-state=checked]_[data-part=item-indicator]::before]:bg-curr" +
"ent [&[role=menuitemcheckbox][data-state=checked]_[data-part=item-indicator]::before]:[clip-path:polygo" +
"n(14%_44%,0_65%,38%_100%,100%_22%,84%_6%,38%_68%)] [&[role=menuitemcheckbox][data-state=indeterminate]_" +
"[data-part=item-indicator]]:border-primary [&[role=menuitemcheckbox][data-state=indeterminate]_[data-pa" +
"rt=item-indicator]]:bg-primary [&[role=menuitemcheckbox][data-state=indeterminate]_[data-part=item-indi" +
"cator]]:text-primary-foreground [&[role=menuitemcheckbox][data-state=indeterminate]_[data-part=item-ind" +
"icator]::before]:content-[''] [&[role=menuitemcheckbox][data-state=indeterminate]_[data-part=item-indic" +
"ator]::before]:w-[0.65rem] [&[role=menuitemcheckbox][data-state=indeterminate]_[data-part=item-indicato" +
"r]::before]:h-[0.12rem] [&[role=menuitemcheckbox][data-state=indeterminate]_[data-part=item-indicator]:" +
":before]:bg-current [&[role=menuitemradio]_[data-part=item-indicator]]:rounded-full [&[role=menuitemrad" +
"io][data-state=checked]_[data-part=item-indicator]]:border-[5px] [&[role=menuitemradio][data-state=chec" +
"ked]_[data-part=item-indicator]]:border-primary [&[role=menuitemradio][data-state=checked]_[data-part=i" +
"tem-indicator]]:bg-card [&_[data-part=item-text]]:grid [&_[data-part=item-text]]:flex-auto [&_[data-par" +
"t=item-text]]:[min-inline-size:0] [&_[data-part=item-description]]:text-muted-foreground [&_[data-part=" +
"item-description]]:text-xs [&_[data-part=item-description]]:[line-height:var(--leading-normal)] [&_[dat" +
"a-part=shortcut]]:ms-auto [&_[data-part=shortcut]]:text-muted-foreground [&_[data-part=shortcut]]:text-" +
"xs [&_[data-part=shortcut]]:leading-none [&_[data-part=shortcut]]:whitespace-nowrap"
}
>
Paste
</ContextMenu.Item>
</ContextMenu.Content>
</ContextMenu.Root>
);
}/* 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('grid gap-md w-max max-w-[min(28rem,calc(100vw_-_2_*_var(--space-lg)))] p-6 border border-border rounded-xl [corner-shape:squircle] 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)] [&[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 rounded-lg bg-popover text-popover-foreground [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)] flex items-center 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 [&_[data-part=item-icon]]:inline-grid [&_[data-part=item-icon]]:place-items-center [&_[data-part=item-icon]]:size-5 [&_[data-part=item-icon]]:flex-[0_0_1.25rem] [&_[data-part=item-indicator]]:inline-grid [&_[data-part=item-indicator]]:place-items-center [&_[data-part=item-indicator]]:size-5 [&_[data-part=item-indicator]]:flex-[0_0_1.25rem] [&_[data-part=item-indicator]>svg]:block [&_[data-part=item-indicator]>svg]:size-full [&[role=menuitemcheckbox]_[data-part=item-indicator]]:border-[length:var(--border-width)] [&[role=menuitemcheckbox]_[data-part=item-indicator]]:border-input [&[role=menuitemcheckbox]_[data-part=item-indicator]]:rounded-xs [&[role=menuitemcheckbox][data-state=checked]_[data-part=item-indicator]]:border-primary [&[role=menuitemcheckbox][data-state=checked]_[data-part=item-indicator]]:bg-primary [&[role=menuitemcheckbox][data-state=checked]_[data-part=item-indicator]]:text-primary-foreground [&[role=menuitemcheckbox][data-state=checked]_[data-part=item-indicator]::before]:size-[0.65rem] [&[role=menuitemcheckbox][data-state=checked]_[data-part=item-indicator]::before]:bg-current [&[role=menuitemcheckbox][data-state=checked]_[data-part=item-indicator]::before]:[clip-path:polygon(14%_44%,0_65%,38%_100%,100%_22%,84%_6%,38%_68%)] [&[role=menuitemcheckbox][data-state=indeterminate]_[data-part=item-indicator]]:border-primary [&[role=menuitemcheckbox][data-state=indeterminate]_[data-part=item-indicator]]:bg-primary [&[role=menuitemcheckbox][data-state=indeterminate]_[data-part=item-indicator]]:text-primary-foreground [&[role=menuitemcheckbox][data-state=indeterminate]_[data-part=item-indicator]::before]:w-[0.65rem] [&[role=menuitemcheckbox][data-state=indeterminate]_[data-part=item-indicator]::before]:h-[0.12rem] [&[role=menuitemcheckbox][data-state=indeterminate]_[data-part=item-indicator]::before]:bg-current [&[role=menuitemradio]_[data-part=item-indicator]]:rounded-full [&[role=menuitemradio][data-state=checked]_[data-part=item-indicator]]:border-[5px] [&[role=menuitemradio][data-state=checked]_[data-part=item-indicator]]:border-primary [&[role=menuitemradio][data-state=checked]_[data-part=item-indicator]]:bg-card [&_[data-part=item-text]]:grid [&_[data-part=item-text]]:flex-auto [&_[data-part=item-text]]:[min-inline-size:0] [&_[data-part=item-description]]:text-muted-foreground [&_[data-part=item-description]]:text-xs [&_[data-part=item-description]]:[line-height:var(--leading-normal)] [&_[data-part=shortcut]]:ms-auto [&_[data-part=shortcut]]:text-muted-foreground [&_[data-part=shortcut]]:text-xs [&_[data-part=shortcut]]:leading-none [&_[data-part=shortcut]]:whitespace-nowrap [block-size:var(--border-width)] [margin-block:var(--space-xs)] [margin-inline:calc(-1_*var(--space-xs))] bg-border');
@source inline("[&[role=menuitemcheckbox][data-state=checked]_[data-part=item-indicator]::before]:content-[''] [&[role=menuitemcheckbox][data-state=indeterminate]_[data-part=item-indicator]::before]: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
ContextMenu.Root
| Свойство | Тип | По умолчанию | Описание |
|---|---|---|---|
children | ReactNode | — | Область триггера и содержимое меню. |
defaultOpen | boolean | — | Начальное состояние открытия неуправляемого меню. |
id | string | — | Идентификатор всплывающего элемента, содержащего меню. |
onOpenChange | PopoverChangeHandler | — | Вызывается при открытии или закрытии меню с причиной и исходным событием. |
open | boolean | — | Состояние открытия меню, делающее его управляемым. |
ContextMenu.Trigger
| Свойство | Тип | По умолчанию | Описание |
|---|---|---|---|
children | ReactNode | — | Область, открывающая меню щелчком правой кнопки мыши. |
className | string | — | Класс отображаемого элемента. |
render | ReactElement | ((props, state) => ReactElement) | — | Заменяет отображаемый элемент, сохраняя поведение и связи доступности. |
ContextMenu.Content
| Свойство | Тип | По умолчанию | Описание |
|---|---|---|---|
children | ReactNode | — | Пункты, подписи и разделители меню. |
className | string | — | Класс отображаемого элемента. |
render | ReactElement | ((props, state) => ReactElement) | — | Заменяет отображаемый элемент, сохраняя поведение и связи доступности. |
ContextMenu.Item
| Свойство | Тип | По умолчанию | Описание |
|---|---|---|---|
children | ReactNode | — | Содержимое пункта. |
className | string | — | Класс отображаемого элемента. |
disabled | boolean | false | Отключает пункт и пропускает его при навигации с клавиатуры. |
onSelect | (event: MenuSelectEvent) => void | — | Вызывается при выборе пункта; вызов preventDefault у события оставляет меню открытым. |
textValue | string | — | Текст для поиска вводом символов, если содержимое пункта не является обычным текстом. |
render | ReactElement | ((props, state) => ReactElement) | — | Заменяет отображаемый элемент, сохраняя поведение и связи доступности. |
ContextMenu.CheckboxItem
| Свойство | Тип | По умолчанию | Описание |
|---|---|---|---|
checked | boolean | "indeterminate" | false | Состояние отметки пункта. |
children | ReactNode | — | Содержимое пункта. |
className | string | — | Класс отображаемого элемента. |
disabled | boolean | false | Отключает пункт и пропускает его при навигации с клавиатуры. |
onCheckedChange | (checked: boolean) => void | — | Вызывается с новым состоянием отметки при выборе пункта. |
textValue | string | — | Текст для поиска вводом символов, если содержимое пункта не является обычным текстом. |
ContextMenu.RadioItem
| Свойство | Тип | По умолчанию | Описание |
|---|---|---|---|
value* | string | — | Значение, выбираемое этим пунктом в меню. |
children | ReactNode | — | Содержимое пункта. |
className | string | — | Класс отображаемого элемента. |
disabled | boolean | false | Отключает пункт и пропускает его при навигации с клавиатуры. |
textValue | string | — | Текст для поиска вводом символов, если содержимое пункта не является обычным текстом. |
ContextMenu.Label
| Свойство | Тип | По умолчанию | Описание |
|---|---|---|---|
children | ReactNode | — | Текст заголовка группы. |
className | string | — | Класс отображаемого элемента. |
ContextMenu.Separator
| Свойство | Тип | По умолчанию | Описание |
|---|---|---|---|
className | string | — | Класс отображаемого элемента. |
ContextMenu.Sub
| Свойство | Тип | По умолчанию | Описание |
|---|---|---|---|
children | ReactNode | — | Триггер подменю и его содержимое. |
ContextMenu.Sub.Trigger
| Свойство | Тип | По умолчанию | Описание |
|---|---|---|---|
children | ReactNode | — | Подпись триггера подменю. |
className | string | — | Класс отображаемого элемента. |
disabled | boolean | false | Отключает триггер и пропускает его при навигации с клавиатуры. |
textValue | string | — | Текст для поиска вводом символов, если содержимое пункта не является обычным текстом. |
ContextMenu.Sub.Content
| Свойство | Тип | По умолчанию | Описание |
|---|---|---|---|
children | ReactNode | — | Пункты подменю. |
className | string | — | Класс отображаемого элемента. |
Клавиатура
| Клавиша | Действие |
|---|---|
| Shift+F10 / Menu key | Открыть у элемента в фокусе |
| ↑ / ↓ | Перемещаться между пунктами |
| Escape | Закрыть и вернуть фокус |
Доступность
Меню открывается в позиции указателя или в позиции, заданной вызовом с клавиатуры.
Привязка стилей
data-statedata-highlighted