@loke/ui
Version:
270 lines (194 loc) • 7.1 kB
Markdown
# Dropdown Menu — Sub-component Reference
All exports from `@loke/ui/dropdown-menu`.
## Root components
### DropdownMenu
```ts
interface DropdownMenuProps {
children?: ReactNode;
defaultOpen?: boolean;
dir?: "ltr" | "rtl";
modal?: boolean; // default: true
onOpenChange?: (open: boolean) => void;
open?: boolean;
}
```
Root context provider. `modal={true}` disables pointer events on the background when open. Wrap `DropdownMenuTrigger` and `DropdownMenuPortal` inside.
### DropdownMenuTrigger
```ts
interface DropdownMenuTriggerProps extends PrimitiveButtonProps {
disabled?: boolean;
}
```
Renders a `<button>` that toggles the menu. Sets `aria-haspopup="menu"`, `aria-expanded`, and `aria-controls`. `Enter`, `Space`, `ArrowDown` open the menu. `PointerDown` toggles.
### DropdownMenuPortal
```ts
interface DropdownMenuPortalProps {
children?: ReactNode;
container?: HTMLElement | null; // default: document.body
forceMount?: true;
}
```
Portals content into the DOM. Wrap `DropdownMenuContent` inside. Required to avoid z-index and overflow clipping issues.
## Content
### DropdownMenuContent
```ts
interface DropdownMenuContentProps
extends Omit<MenuContentProps, "onEntryFocus"> {
// All PopperContent positioning props:
side?: "top" | "right" | "bottom" | "left"; // default: "bottom"
sideOffset?: number; // default: 0
align?: "start" | "center" | "end"; // default: "center"
alignOffset?: number;
avoidCollisions?: boolean; // default: true
collisionBoundary?: Element | Element[] | null;
collisionPadding?: number | Partial<Record<Side, number>>;
arrowPadding?: number;
sticky?: "partial" | "always";
hideWhenDetached?: boolean;
// DismissableLayer props:
onEscapeKeyDown?: (event: KeyboardEvent) => void;
onPointerDownOutside?: (event: PointerDownOutsideEvent) => void;
onFocusOutside?: (event: FocusOutsideEvent) => void;
onInteractOutside?: (event: PointerDownOutsideEvent | FocusOutsideEvent) => void;
onCloseAutoFocus?: (event: Event) => void;
// Menu-specific:
loop?: boolean; // default: false — whether keyboard nav wraps
}
```
CSS custom properties set on this element:
| Property | Description |
|---|---|
| `--loke-dropdown-menu-content-available-height` | Viewport space above/below trigger |
| `--loke-dropdown-menu-content-available-width` | Viewport space left/right of trigger |
| `--loke-dropdown-menu-content-transform-origin` | Correct origin for scale animations |
| `--loke-dropdown-menu-trigger-height` | Height of the trigger element |
| `--loke-dropdown-menu-trigger-width` | Width of the trigger element |
## Items
### DropdownMenuItem
```ts
interface DropdownMenuItemProps extends PrimitiveDivProps {
disabled?: boolean;
onSelect?: (event: Event) => void;
textValue?: string; // used for typeahead; defaults to textContent
}
```
Standard menu item. Fires `onSelect` on pointer-up or Enter/Space, then auto-closes the menu. Call `event.preventDefault()` in `onSelect` to prevent auto-close.
### DropdownMenuCheckboxItem
```ts
interface DropdownMenuCheckboxItemProps extends PrimitiveDivProps {
checked?: boolean | "indeterminate";
disabled?: boolean;
onCheckedChange?: (checked: boolean) => void;
onSelect?: (event: Event) => void;
textValue?: string;
}
```
Toggle item. `data-state="checked"` | `"unchecked"` | `"indeterminate"`. Does not auto-close by default when `onSelect` is not prevented — call `event.preventDefault()` inside `onSelect` to keep menu open after toggle.
### DropdownMenuRadioGroup
```ts
interface DropdownMenuRadioGroupProps extends PrimitiveDivProps {
onValueChange?: (value: string) => void;
value?: string;
}
```
Groups `DropdownMenuRadioItem` elements. Manages a single selected value.
### DropdownMenuRadioItem
```ts
interface DropdownMenuRadioItemProps extends PrimitiveDivProps {
disabled?: boolean;
onSelect?: (event: Event) => void;
textValue?: string;
value: string; // required
}
```
Radio-style item. `data-state="checked"` | `"unchecked"`. Must be inside `DropdownMenuRadioGroup`. Fires `onValueChange` on the group when selected.
### DropdownMenuItemIndicator
```ts
interface DropdownMenuItemIndicatorProps extends PrimitiveSpanProps {
forceMount?: true;
}
```
Renders only when the parent `CheckboxItem` or `RadioItem` is checked. By default unmounts when unchecked. Use `forceMount` to keep it mounted for exit animations. Style with `data-state="checked"` / `"unchecked"`.
## Structure
### DropdownMenuGroup
```ts
interface DropdownMenuGroupProps extends PrimitiveDivProps {}
```
Semantic grouping container. Renders a `<div>` with no additional behavior. Use alongside `DropdownMenuLabel` to label a group.
### DropdownMenuLabel
```ts
interface DropdownMenuLabelProps extends PrimitiveDivProps {}
```
Non-interactive label for a group. Not focusable, not selectable.
### DropdownMenuSeparator
```ts
interface DropdownMenuSeparatorProps extends PrimitiveDivProps {}
```
Visual and semantic separator. Renders with `role="separator"`.
### DropdownMenuArrow
```ts
interface DropdownMenuArrowProps extends PrimitiveSVGProps {
height?: number; // default: 5
width?: number; // default: 10
}
```
SVG arrow pointing toward the trigger. Must be inside `DropdownMenuContent`.
## Submenus
### DropdownMenuSub
```ts
interface DropdownMenuSubProps {
children?: ReactNode;
defaultOpen?: boolean;
onOpenChange?: (open: boolean) => void;
open?: boolean;
}
```
Submenu root. Manages open state for the nested `DropdownMenuSubTrigger` + `DropdownMenuSubContent` pair.
### DropdownMenuSubTrigger
```ts
interface DropdownMenuSubTriggerProps extends PrimitiveDivProps {
disabled?: boolean;
textValue?: string;
}
```
Item that opens the submenu on pointer move or Enter/ArrowRight. Renders an arrow indicator automatically. Must be inside `DropdownMenuSub`.
### DropdownMenuSubContent
```ts
interface DropdownMenuSubContentProps {
// Same positioning/dismissal props as DropdownMenuContent
avoidCollisions?: boolean;
collisionBoundary?: Element | Element[] | null;
collisionPadding?: number | Partial<Record<Side, number>>;
forceMount?: true;
hideWhenDetached?: boolean;
loop?: boolean;
onEscapeKeyDown?: (event: KeyboardEvent) => void;
onFocusOutside?: (event: FocusOutsideEvent) => void;
onInteractOutside?: (event: PointerDownOutsideEvent | FocusOutsideEvent) => void;
onPointerDownOutside?: (event: PointerDownOutsideEvent) => void;
sticky?: "partial" | "always";
}
```
Content panel for the submenu. Wrap in `DropdownMenuPortal`. Sets the same `--loke-dropdown-menu-*` CSS custom properties as `DropdownMenuContent`.
## Scope utility
### createDropdownMenuScope
```ts
function createDropdownMenuScope(): CreateScope;
```
For composing `DropdownMenu` inside other compound components. See the [context-and-collection](../../context-and-collection/SKILL.md) skill for scope threading patterns.