Components for creating menus with radio and checkbox selection functionality. These components enable building interactive menus with selectable options and state management.
Container component that manages the state of multiple selectable menu options, supporting both radio (single selection) and checkbox (multiple selection) modes.
/**
* Container for selectable menu options with state management
* @param props - Option group configuration and children
*/
const MenuOptionGroup: React.FC<MenuOptionGroupProps>;
interface MenuOptionGroupProps extends UseMenuOptionGroupProps, Omit<MenuGroupProps, "value" | "defaultValue" | "onChange"> {
/** Group title displayed above options */
title?: string;
/** CSS class name for styling */
className?: string;
}
interface UseMenuOptionGroupProps {
/** Current selected value(s) - string for radio, string[] for checkbox */
value?: string | string[];
/** Default selected value(s) for uncontrolled usage */
defaultValue?: string | string[];
/** Selection type - radio allows single selection, checkbox allows multiple */
type?: "radio" | "checkbox";
/** Callback fired when selection changes */
onChange?: (value: string | string[]) => void;
/** Child MenuItemOption components */
children?: React.ReactNode;
}Usage Examples:
import { Menu, MenuButton, MenuList, MenuOptionGroup, MenuItemOption } from "@chakra-ui/menu";
// Radio group (single selection)
function RadioOptionGroup() {
const [sortOrder, setSortOrder] = useState("asc");
return (
<Menu closeOnSelect={false}>
<MenuButton>Sort Options</MenuButton>
<MenuList>
<MenuOptionGroup
title="Sort Order"
type="radio"
value={sortOrder}
onChange={(value) => setSortOrder(value as string)}
>
<MenuItemOption value="asc">Ascending</MenuItemOption>
<MenuItemOption value="desc">Descending</MenuItemOption>
<MenuItemOption value="alpha">Alphabetical</MenuItemOption>
</MenuOptionGroup>
</MenuList>
</Menu>
);
}
// Checkbox group (multiple selection)
function CheckboxOptionGroup() {
const [filters, setFilters] = useState(["active"]);
return (
<Menu closeOnSelect={false}>
<MenuButton>Filter Options</MenuButton>
<MenuList>
<MenuOptionGroup
title="Status Filters"
type="checkbox"
value={filters}
onChange={(value) => setFilters(value as string[])}
>
<MenuItemOption value="active">Active Items</MenuItemOption>
<MenuItemOption value="completed">Completed Items</MenuItemOption>
<MenuItemOption value="pending">Pending Items</MenuItemOption>
<MenuItemOption value="archived">Archived Items</MenuItemOption>
</MenuOptionGroup>
</MenuList>
</Menu>
);
}
// Uncontrolled usage
function UncontrolledOptions() {
return (
<Menu closeOnSelect={false}>
<MenuButton>Preferences</MenuButton>
<MenuList>
<MenuOptionGroup
title="Theme"
type="radio"
defaultValue="light"
>
<MenuItemOption value="light">Light Mode</MenuItemOption>
<MenuItemOption value="dark">Dark Mode</MenuItemOption>
<MenuItemOption value="auto">Auto</MenuItemOption>
</MenuOptionGroup>
</MenuList>
</Menu>
);
}Individual selectable menu item that displays checked/unchecked state and integrates with MenuOptionGroup for state management.
/**
* Selectable menu item with checkbox/radio functionality
* @param props - Option item properties including selection state
* @param ref - Forward ref to the menu item element
*/
const MenuItemOption: React.ForwardRefExoticComponent<MenuItemOptionProps>;
interface MenuItemOptionProps extends UseMenuOptionOptions, Omit<MenuItemProps, keyof UseMenuOptionOptions | "icon"> {
/** Custom icon to display instead of default check/radio icon */
icon?: React.ReactElement | null;
/** Spacing between icon and text */
iconSpacing?: SystemProps["mr"];
/** Item content */
children?: React.ReactNode;
}
interface UseMenuOptionOptions {
/** The value associated with this option */
value?: string;
/** Whether this option is currently selected */
isChecked?: boolean;
/** Selection type - radio or checkbox */
type?: "radio" | "checkbox";
/** Child content */
children?: React.ReactNode;
}Usage Examples:
// Basic option items
<MenuOptionGroup title="Options" type="radio">
<MenuItemOption value="option1">Option 1</MenuItemOption>
<MenuItemOption value="option2">Option 2</MenuItemOption>
<MenuItemOption value="option3">Option 3</MenuItemOption>
</MenuOptionGroup>
// Custom icons
<MenuOptionGroup title="Status" type="checkbox">
<MenuItemOption value="online" icon={<CheckCircleIcon color="green.500" />}>
Online
</MenuItemOption>
<MenuItemOption value="busy" icon={<WarningIcon color="yellow.500" />}>
Busy
</MenuItemOption>
<MenuItemOption value="offline" icon={<CloseIcon color="red.500" />}>
Offline
</MenuItemOption>
</MenuOptionGroup>
// No icon (icon={null})
<MenuOptionGroup title="Simple Options" type="checkbox">
<MenuItemOption value="opt1" icon={null}>
Plain Option 1
</MenuItemOption>
<MenuItemOption value="opt2" icon={null}>
Plain Option 2
</MenuItemOption>
</MenuOptionGroup>
// Manual selection control
function ManualOptions() {
const [selectedItems, setSelectedItems] = useState(new Set());
const handleToggle = (value) => {
const newSelected = new Set(selectedItems);
if (newSelected.has(value)) {
newSelected.delete(value);
} else {
newSelected.add(value);
}
setSelectedItems(newSelected);
};
return (
<MenuList>
<MenuItemOption
value="item1"
isChecked={selectedItems.has("item1")}
onClick={() => handleToggle("item1")}
>
Manual Item 1
</MenuItemOption>
<MenuItemOption
value="item2"
isChecked={selectedItems.has("item2")}
onClick={() => handleToggle("item2")}
>
Manual Item 2
</MenuItemOption>
</MenuList>
);
}function MixedMenu() {
const [sortBy, setSortBy] = useState("name");
const [filters, setFilters] = useState(["active"]);
return (
<Menu closeOnSelect={false}>
<MenuButton>Table Options</MenuButton>
<MenuList>
<MenuItem>Export Data</MenuItem>
<MenuItem>Print Table</MenuItem>
<MenuDivider />
<MenuOptionGroup
title="Sort By"
type="radio"
value={sortBy}
onChange={(value) => setSortBy(value as string)}
>
<MenuItemOption value="name">Name</MenuItemOption>
<MenuItemOption value="date">Date Created</MenuItemOption>
<MenuItemOption value="size">File Size</MenuItemOption>
</MenuOptionGroup>
<MenuDivider />
<MenuOptionGroup
title="Show"
type="checkbox"
value={filters}
onChange={(value) => setFilters(value as string[])}
>
<MenuItemOption value="active">Active Items</MenuItemOption>
<MenuItemOption value="hidden">Hidden Items</MenuItemOption>
<MenuItemOption value="deleted">Deleted Items</MenuItemOption>
</MenuOptionGroup>
</MenuList>
</Menu>
);
}function FormMenu({ formData, updateFormData }) {
return (
<Menu closeOnSelect={false}>
<MenuButton>User Preferences</MenuButton>
<MenuList>
<MenuOptionGroup
title="Notification Settings"
type="checkbox"
value={formData.notifications}
onChange={(notifications) =>
updateFormData({ ...formData, notifications })
}
>
<MenuItemOption value="email">Email Notifications</MenuItemOption>
<MenuItemOption value="push">Push Notifications</MenuItemOption>
<MenuItemOption value="sms">SMS Notifications</MenuItemOption>
</MenuOptionGroup>
<MenuDivider />
<MenuOptionGroup
title="Privacy Level"
type="radio"
value={formData.privacy}
onChange={(privacy) =>
updateFormData({ ...formData, privacy })
}
>
<MenuItemOption value="public">Public</MenuItemOption>
<MenuItemOption value="friends">Friends Only</MenuItemOption>
<MenuItemOption value="private">Private</MenuItemOption>
</MenuOptionGroup>
</MenuList>
</Menu>
);
}function TableFilterMenu({ columns, visibleColumns, onToggleColumn }) {
return (
<Menu closeOnSelect={false}>
<MenuButton rightIcon={<ChevronDownIcon />}>
Show Columns
</MenuButton>
<MenuList>
<MenuOptionGroup
title="Visible Columns"
type="checkbox"
value={visibleColumns}
onChange={onToggleColumn}
>
{columns.map((column) => (
<MenuItemOption key={column.id} value={column.id}>
{column.label}
</MenuItemOption>
))}
</MenuOptionGroup>
</MenuList>
</Menu>
);
}function SettingsMenu() {
const [settings, setSettings] = useState({
theme: "light",
features: ["autoSave", "spellCheck"]
});
const updateSetting = (key, value) => {
setSettings(prev => ({ ...prev, [key]: value }));
};
return (
<Menu closeOnSelect={false}>
<MenuButton>Settings</MenuButton>
<MenuList minWidth="240px">
<MenuOptionGroup
title="Theme"
type="radio"
value={settings.theme}
onChange={(value) => updateSetting("theme", value)}
>
<MenuItemOption value="light">Light Theme</MenuItemOption>
<MenuItemOption value="dark">Dark Theme</MenuItemOption>
<MenuItemOption value="system">System Default</MenuItemOption>
</MenuOptionGroup>
<MenuDivider />
<MenuOptionGroup
title="Features"
type="checkbox"
value={settings.features}
onChange={(value) => updateSetting("features", value)}
>
<MenuItemOption value="autoSave">Auto Save</MenuItemOption>
<MenuItemOption value="spellCheck">Spell Check</MenuItemOption>
<MenuItemOption value="wordWrap">Word Wrap</MenuItemOption>
<MenuItemOption value="lineNumbers">Line Numbers</MenuItemOption>
</MenuOptionGroup>
</MenuList>
</Menu>
);
}