Skip to content
Merged
30 changes: 30 additions & 0 deletions apps/www/src/content/docs/components/context-menu/demo.ts
Original file line number Diff line number Diff line change
Expand Up @@ -239,3 +239,33 @@ function ControlledContextMenu() {
);
}`
};

export const selectionDemo = {
type: 'code',
code: `
function SelectionContextMenu() {
const [showGrid, setShowGrid] = React.useState(true);
const [sort, setSort] = React.useState("name");

return (
<ContextMenu>
<ContextMenu.Trigger style={{ padding: "2em 4em", border: "1px dashed var(--rs-color-border-base-primary)", borderRadius: "var(--rs-radius-2)" }}>
<Text>Right click here</Text>
</ContextMenu.Trigger>
<ContextMenu.Content>
<ContextMenu.CheckboxItem checked={showGrid} onCheckedChange={setShowGrid}>
Show grid
</ContextMenu.CheckboxItem>
<ContextMenu.Separator />
<ContextMenu.RadioGroup value={sort} onValueChange={setSort}>
<ContextMenu.Label>Sort by</ContextMenu.Label>
<ContextMenu.RadioItem value="name">Name</ContextMenu.RadioItem>
<ContextMenu.RadioItem value="date">Date</ContextMenu.RadioItem>
</ContextMenu.RadioGroup>
<ContextMenu.Separator />
<ContextMenu.LinkItem href="#docs">Open docs</ContextMenu.LinkItem>
</ContextMenu.Content>
</ContextMenu>
);
}`
};
42 changes: 41 additions & 1 deletion apps/www/src/content/docs/components/context-menu/index.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import {
submenuDemo,
autocompleteDemo,
controlledDemo,
selectionDemo,
} from "./demo.ts";

<Demo data={playground} />
Expand Down Expand Up @@ -59,6 +60,12 @@ Use `ContextMenu.Submenu`, `ContextMenu.SubmenuTrigger`, and `ContextMenu.Submen

<Demo data={submenuDemo} />

### Checkbox, radio, and link items

`ContextMenu.CheckboxItem`, `ContextMenu.RadioGroup`, `ContextMenu.RadioItem`, and `ContextMenu.LinkItem` work the same way as in [Menu](/docs/components/menu#checkbox-items). Checkbox and radio items keep the menu open on click. Link items render an `<a>` element.

<Demo data={selectionDemo} />

### Autocomplete

Pass `autocomplete` to the ContextMenu root. Each menu manages its own autocomplete state.
Expand Down Expand Up @@ -104,9 +111,33 @@ Renders as a `role='option'` when used in an autocomplete menu. By default, the

<auto-type-table path="./props.ts" name="ContextMenuItemProps" />

### CheckboxItem

A menu item that toggles a setting on or off. Renders a check mark before the label when checked.

<auto-type-table path="./props.ts" name="ContextMenuCheckboxItemProps" />

### RadioGroup

Groups related radio items and holds the selected value.

<auto-type-table path="./props.ts" name="ContextMenuRadioGroupProps" />

### RadioItem

A menu item that works like a radio button in a `ContextMenu.RadioGroup`. Renders a dot before the label when checked. The `value` prop is also used for search matching when it is a string.

<auto-type-table path="./props.ts" name="ContextMenuRadioItemProps" />

### LinkItem

A menu item that renders an `<a>` element. Pass a router link to `render` to use client-side routing.

<auto-type-table path="./props.ts" name="ContextMenuLinkItemProps" />

### Group

A way to group related menu items together. When filtering is active, the group wrapper is removed and items are rendered flat.
A way to group related menu items together. When filtering is active, the group label is hidden.

<auto-type-table path="./props.ts" name="ContextMenuGroupProps" />

Expand Down Expand Up @@ -165,6 +196,12 @@ Every rendered part carries a stable `data-slot` attribute for [styling and test
| `context-menu-group` | `ContextMenu.Group` wrapper |
| `context-menu-label` | `ContextMenu.Label` |
| `context-menu-separator` | `ContextMenu.Separator` |
| `context-menu-checkbox-item` | Each `ContextMenu.CheckboxItem` |
| `context-menu-checkbox-item-indicator` | Check mark inside a checkbox item |
| `context-menu-radio-group` | `ContextMenu.RadioGroup` wrapper |
| `context-menu-radio-item` | Each `ContextMenu.RadioItem` |
| `context-menu-radio-item-indicator` | Dot inside a radio item |
| `context-menu-link-item` | Each `ContextMenu.LinkItem` |
| `context-menu-empty-state` | `ContextMenu.EmptyState` |
| `menu-subtrigger` | `ContextMenu.SubmenuTrigger` (shared with `Menu`'s internals) |
| `menu-cell-leading-icon` | Leading icon inside an item or submenu trigger (when provided; shared with `Menu`'s internals) |
Expand All @@ -184,3 +221,6 @@ Every rendered part carries a stable `data-slot` attribute for [styling and test
arrow keys move the highlight, and Escape first closes an open submenu.
- `ContextMenu.Label` must be wrapped in `ContextMenu.Group` so the group is
labelled via `aria-labelledby`.
- Checkbox items use `role="menuitemcheckbox"` and radio items use
`role="menuitemradio"`, both with `aria-checked`. In a searchable menu they
render as `role="option"` and keep `aria-checked`.
107 changes: 107 additions & 0 deletions apps/www/src/content/docs/components/context-menu/props.ts
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,113 @@ export interface ContextMenuSeparatorProps {
className?: string;
}

export interface ContextMenuCheckboxItemProps {
/** Whether the item is checked (controlled) */
checked?: boolean;

/** Whether the item is checked by default (uncontrolled)
* @default false
*/
defaultChecked?: boolean;

/** Callback fired when the checked state changes */
onCheckedChange?: (checked: boolean) => void;

/** Whether to close the menu when the item is clicked
* @default false
*/
closeOnClick?: boolean;

/** Icon element to display before item text */
leadingIcon?: ReactNode;

/** Icon element to display after item text */
trailingIcon?: ReactNode;

/** Whether the item is disabled */
disabled?: boolean;

/** Value of the item used for autocomplete matching. If not provided, `children` text content is used. */
value?: string;

/** Additional CSS class names */
className?: string;

/** Render a custom element using Base UI's render prop pattern. Replaces the default layout and check mark. */
render?: ReactElement;
}

export interface ContextMenuRadioGroupProps {
/** The value of the checked radio item (controlled) */
value?: unknown;

/** The value of the radio item checked by default (uncontrolled) */
defaultValue?: unknown;

/** Callback fired when the checked radio item changes */
onValueChange?: (value: unknown) => void;

/** Whether all radio items in the group are disabled
* @default false
*/
disabled?: boolean;

/** Additional CSS class names */
className?: string;
}

export interface ContextMenuRadioItemProps {
/** Value of the radio item. Also used for autocomplete matching when it is a string. */
value: unknown;

/** Whether to close the menu when the item is clicked
* @default false
*/
closeOnClick?: boolean;

/** Icon element to display before item text */
leadingIcon?: ReactNode;

/** Icon element to display after item text */
trailingIcon?: ReactNode;

/** Whether the item is disabled */
disabled?: boolean;

/** Additional CSS class names */
className?: string;

/** Render a custom element using Base UI's render prop pattern. Replaces the default layout and dot. */
render?: ReactElement;
}

export interface ContextMenuLinkItemProps {
/** The URL the link points to */
href?: string;

/** Whether to close the menu when the link is clicked
* @default false
*/
closeOnClick?: boolean;

/** Icon element to display before item text */
leadingIcon?: ReactNode;

/** Icon element to display after item text */
trailingIcon?: ReactNode;

/** Value of the item used for autocomplete matching. If not provided, `children` text content is used. */
value?: string;

/** Additional CSS class names */
className?: string;

/** The link element to render, for example a router link. The item keeps its layout and icons.
* @default <a />
*/
render?: ReactElement;
}

export interface ContextMenuEmptyStateProps {
/** React nodes to render in empty state */
children?: ReactNode;
Expand Down
62 changes: 62 additions & 0 deletions apps/www/src/content/docs/components/menu/demo.ts
Original file line number Diff line number Diff line change
Expand Up @@ -520,3 +520,65 @@ function ControlledMenu() {
);
}`
};

export const checkboxDemo = {
type: 'code',
code: `
function CheckboxMenu() {
const [showGrid, setShowGrid] = React.useState(true);

return (
<Menu>
<Menu.Trigger render={<Button color="neutral" />}>View</Menu.Trigger>
<Menu.Content>
<Menu.CheckboxItem checked={showGrid} onCheckedChange={setShowGrid}>
Show grid
</Menu.CheckboxItem>
<Menu.CheckboxItem defaultChecked>Show rulers</Menu.CheckboxItem>
<Menu.CheckboxItem disabled>Show guides</Menu.CheckboxItem>
</Menu.Content>
</Menu>
);
}`
};

export const radioDemo = {
type: 'code',
code: `
function RadioMenu() {
const [layout, setLayout] = React.useState("list");

return (
<Menu>
<Menu.Trigger render={<Button color="neutral" />}>Layout</Menu.Trigger>
<Menu.Content>
<Menu.RadioGroup value={layout} onValueChange={setLayout}>
<Menu.Label>Layout</Menu.Label>
<Menu.RadioItem value="list">List</Menu.RadioItem>
<Menu.RadioItem value="board">Board</Menu.RadioItem>
<Menu.RadioItem value="timeline">Timeline</Menu.RadioItem>
</Menu.RadioGroup>
</Menu.Content>
</Menu>
);
}`
};

export const linkDemo = {
type: 'code',
code: `
<Menu>
<Menu.Trigger render={<Button color="neutral" />}>Go to</Menu.Trigger>
<Menu.Content>
<Menu.LinkItem href="#projects">Projects</Menu.LinkItem>
<Menu.LinkItem href="#settings">Settings</Menu.LinkItem>
<Menu.LinkItem
href="https://github.com/raystack/apsara"
target="_blank"
rel="noreferrer"
closeOnClick>
GitHub
</Menu.LinkItem>
</Menu.Content>
</Menu>`
};
66 changes: 64 additions & 2 deletions apps/www/src/content/docs/components/menu/index.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,9 @@ import {
autocompleteDemo,
linearDemo,
controlledDemo,
checkboxDemo,
radioDemo,
linkDemo,
} from "./demo.ts";

<Demo data={playground} />
Expand Down Expand Up @@ -60,6 +63,30 @@ Use `Menu.Submenu`, `Menu.SubmenuTrigger`, and `Menu.SubmenuContent` to create n

<Demo data={submenuDemo} />

### Checkbox items

Use `Menu.CheckboxItem` for a setting that turns on or off. Clicking it toggles the check mark and keeps the menu open. Pass `checked` and `onCheckedChange` to control it.

<Demo data={checkboxDemo} />

### Radio items

Wrap `Menu.RadioItem` parts in a `Menu.RadioGroup`. Only one item in the group is checked at a time. Clicking an item keeps the menu open.

<Demo data={radioDemo} />

### Link items

Use `Menu.LinkItem` to navigate. It renders an `<a>` element. The menu stays open on click by default. Pass `closeOnClick` to close it, for example with client-side routing.

To use a router link, pass it to `render`. The item keeps its layout and icons.

```tsx
<Menu.LinkItem render={<NextLink href="/projects" />}>Projects</Menu.LinkItem>
```

<Demo data={linkDemo} />

### Autocomplete

Pass `autocomplete` to the Menu root. Each menu manages its own autocomplete state.
Expand Down Expand Up @@ -114,13 +141,37 @@ The container that holds the menu items. When autocomplete is enabled, renders a

Individual clickable options within the menu. Built on top of [Base UI Menu.Item](https://base-ui.com/react/components/menu).

Renders as a `role='option' `when used in an autocomplete menu. By default, the item's `children` text content is used for matching, which can be overridden by passing a `value` prop.
Renders as a `role='option'` when used in an autocomplete menu. By default, the item's `children` text content is used for matching, which can be overridden by passing a `value` prop.

<auto-type-table path="./props.ts" name="MenuItemProps" />

### CheckboxItem

A menu item that toggles a setting on or off. Renders a check mark before the label when checked. Built on [Base UI Menu.CheckboxItem](https://base-ui.com/react/components/menu).

<auto-type-table path="./props.ts" name="MenuCheckboxItemProps" />

### RadioGroup

Groups related radio items and holds the selected value.

<auto-type-table path="./props.ts" name="MenuRadioGroupProps" />

### RadioItem

A menu item that works like a radio button in a `Menu.RadioGroup`. Renders a dot before the label when checked. The `value` prop is also used for search matching when it is a string.

<auto-type-table path="./props.ts" name="MenuRadioItemProps" />

### LinkItem

A menu item that renders an `<a>` element. Built on [Base UI Menu.LinkItem](https://base-ui.com/react/components/menu).

<auto-type-table path="./props.ts" name="MenuLinkItemProps" />

### Group

A way to group related menu items together. When filtering is active, the group wrapper is removed and items are rendered flat.
A way to group related menu items together. When filtering is active, the group label is hidden.

<auto-type-table path="./props.ts" name="MenuGroupProps" />

Expand Down Expand Up @@ -181,6 +232,12 @@ Every rendered part carries a stable `data-slot` attribute for [styling and test
| `menu-group` | `Menu.Group` wrapper |
| `menu-label` | `Menu.Label` |
| `menu-separator` | `Menu.Separator` |
| `menu-checkbox-item` | Each `Menu.CheckboxItem` |
| `menu-checkbox-item-indicator` | Check mark inside a checkbox item |
| `menu-radio-group` | `Menu.RadioGroup` wrapper |
| `menu-radio-item` | Each `Menu.RadioItem` |
| `menu-radio-item-indicator` | Dot inside a radio item |
| `menu-link-item` | Each `Menu.LinkItem` |
| `menu-empty-state` | `Menu.EmptyState` |
| `menu-subtrigger` | `Menu.SubmenuTrigger` |

Expand All @@ -199,3 +256,8 @@ Every rendered part carries a stable `data-slot` attribute for [styling and test
submenu, and Escape first closes an open submenu.
- `Menu.Label` must be wrapped in `Menu.Group` so the group is labelled via
`aria-labelledby`.
- `Menu.CheckboxItem` uses `role="menuitemcheckbox"` and `Menu.RadioItem` uses
`role="menuitemradio"`, both with `aria-checked`. In a searchable menu they
render as `role="option"` and keep `aria-checked`.
- `Menu.LinkItem` renders an `<a>` with `role="menuitem"`, or `role="option"`
in a searchable menu.
Loading
Loading