Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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