menuitemcheckbox
A checkable menuitem with three possible values: true, false, or mixed. Used for toggleable options within dropdown menus.
Overview
The menuitemcheckbox role defines a checkable menu item within a menu. Unlike a regular menuitem, it maintains a checked state that can be toggled by the user.
This role supports three states via aria-checked:
true- Item is checked/selectedfalse- Item is unchecked/deselectedmixed- Partially checked (for parent items with some children checked)
When to Use menuitemcheckbox
Use menuitemcheckbox when you need toggleable options in a dropdown menu where multiple options can be selected simultaneously. Common examples include text formatting menus (Bold, Italic, Underline) and view option menus (Show Toolbar, Show Sidebar).
Live Demo: Interactive Menu Checkboxes
Text Formatting Menu
Current selections: Italic
View Options Menu
File Selection (Mixed State Example)
Notice the "Select All" shows a mixed state (−) when only some files are selected.
Try with keyboard: Open a menu, then use ↑/↓ to navigate, Enter or Space to toggle, and Escape to close.
Code Examples
Basic Usage
<!-- Basic menuitemcheckbox in a dropdown menu -->
<button
aria-haspopup="menu"
aria-expanded="false"
id="menu-button"
>
Format Options
</button>
<div role="menu" aria-labelledby="menu-button">
<div
role="menuitemcheckbox"
aria-checked="false"
tabindex="-1"
>
Bold
</div>
<div
role="menuitemcheckbox"
aria-checked="true"
tabindex="-1"
>
Italic
</div>
<div
role="menuitemcheckbox"
aria-checked="false"
tabindex="-1"
>
Underline
</div>
</div>Mixed State (Tri-State)
<!-- menuitemcheckbox with mixed state (tri-state) -->
<div role="menu" aria-label="File Selection">
<!-- Parent checkbox with mixed state -->
<div
role="menuitemcheckbox"
aria-checked="mixed"
tabindex="-1"
>
Select All Files
</div>
<!-- Child checkboxes -->
<div
role="menuitemcheckbox"
aria-checked="true"
tabindex="-1"
>
document.pdf
</div>
<div
role="menuitemcheckbox"
aria-checked="false"
tabindex="-1"
>
image.png
</div>
<div
role="menuitemcheckbox"
aria-checked="true"
tabindex="-1"
>
notes.txt
</div>
</div>
<!--
aria-checked="mixed" indicates partial selection:
- When some (but not all) children are selected
- Screen readers announce "partially checked" or "mixed"
-->Keyboard Support
<!-- Accessible menuitemcheckbox with keyboard support -->
<script>
const menu = document.querySelector('[role="menu"]');
const items = menu.querySelectorAll('[role="menuitemcheckbox"]');
let currentIndex = 0;
menu.addEventListener('keydown', (e) => {
switch (e.key) {
case 'ArrowDown':
e.preventDefault();
currentIndex = (currentIndex + 1) % items.length;
items[currentIndex].focus();
break;
case 'ArrowUp':
e.preventDefault();
currentIndex = (currentIndex - 1 + items.length) % items.length;
items[currentIndex].focus();
break;
case 'Home':
e.preventDefault();
currentIndex = 0;
items[currentIndex].focus();
break;
case 'End':
e.preventDefault();
currentIndex = items.length - 1;
items[currentIndex].focus();
break;
case 'Enter':
case ' ':
e.preventDefault();
toggleCheckbox(items[currentIndex]);
break;
case 'Escape':
e.preventDefault();
closeMenu();
break;
}
});
function toggleCheckbox(item) {
const current = item.getAttribute('aria-checked');
// For mixed state, clicking toggles to true
const newState = current === 'true' ? 'false' : 'true';
item.setAttribute('aria-checked', newState);
}
</script>React Component
// React menuitemcheckbox Component
import { useState, useRef, useEffect, useCallback } from 'react';
interface MenuItem {
id: string;
label: string;
checked: boolean | 'mixed';
}
function MenuWithCheckboxes() {
const [isOpen, setIsOpen] = useState(false);
const [items, setItems] = useState<MenuItem[]>([
{ id: 'bold', label: 'Bold', checked: false },
{ id: 'italic', label: 'Italic', checked: true },
{ id: 'underline', label: 'Underline', checked: false },
]);
const [focusedIndex, setFocusedIndex] = useState(0);
const menuRef = useRef<HTMLDivElement>(null);
const buttonRef = useRef<HTMLButtonElement>(null);
const toggleItem = useCallback((id: string) => {
setItems(prev => prev.map(item => ({
...item,
checked: item.id === id
? (item.checked === true ? false : true)
: item.checked
})));
}, []);
const handleKeyDown = (e: React.KeyboardEvent) => {
switch (e.key) {
case 'ArrowDown':
e.preventDefault();
setFocusedIndex(prev => (prev + 1) % items.length);
break;
case 'ArrowUp':
e.preventDefault();
setFocusedIndex(prev =>
(prev - 1 + items.length) % items.length
);
break;
case 'Enter':
case ' ':
e.preventDefault();
toggleItem(items[focusedIndex].id);
break;
case 'Escape':
setIsOpen(false);
buttonRef.current?.focus();
break;
}
};
// Focus first item when menu opens
useEffect(() => {
if (isOpen) {
setFocusedIndex(0);
menuRef.current?.focus();
}
}, [isOpen]);
return (
<div className="relative">
<button
ref={buttonRef}
aria-haspopup="menu"
aria-expanded={isOpen}
onClick={() => setIsOpen(!isOpen)}
>
Format Options
</button>
{isOpen && (
<div
ref={menuRef}
role="menu"
aria-label="Format Options"
tabIndex={-1}
onKeyDown={handleKeyDown}
className="absolute mt-1 bg-white shadow-lg rounded"
>
{items.map((item, index) => (
<div
key={item.id}
role="menuitemcheckbox"
aria-checked={item.checked}
tabIndex={index === focusedIndex ? 0 : -1}
onClick={() => toggleItem(item.id)}
className={`px-4 py-2 flex items-center gap-2 ${
index === focusedIndex ? 'bg-blue-100' : ''
}`}
>
<span aria-hidden="true">
{item.checked === true ? '☑' :
item.checked === 'mixed' ? '▣' : '☐'}
</span>
{item.label}
</div>
))}
</div>
)}
</div>
);
}Grouped Menu Items
<!-- Grouped menuitemcheckbox items -->
<div role="menu" aria-label="Document Settings">
<!-- Group: Text Formatting -->
<div role="group" aria-label="Text Formatting">
<div role="presentation" class="menu-group-label">
Text Formatting
</div>
<div role="menuitemcheckbox" aria-checked="true" tabindex="-1">
Bold
</div>
<div role="menuitemcheckbox" aria-checked="false" tabindex="-1">
Italic
</div>
</div>
<!-- Separator -->
<div role="separator"></div>
<!-- Group: View Options -->
<div role="group" aria-label="View Options">
<div role="presentation" class="menu-group-label">
View Options
</div>
<div role="menuitemcheckbox" aria-checked="true" tabindex="-1">
Show Toolbar
</div>
<div role="menuitemcheckbox" aria-checked="false" tabindex="-1">
Show Sidebar
</div>
</div>
</div>
<!--
Use role="group" to semantically group related items
Use role="separator" between groups
Group labels should use role="presentation"
-->Keyboard Support
Required & Supported Attributes
Required Attributes
aria-checkedRequired. Indicates the current checked state of the menu item. Must be one of: true, false, or mixed.
Supported Attributes
aria-checkedRequiredRequired. Current checked state (true/false/mixed)
aria-disabledIndicates item is disabled and not interactive
aria-labelAccessible name for the menu item
aria-labelledbyReferences element(s) that label the item
aria-describedbyReferences element(s) that describe the item
tabindexShould be -1 (focus managed by menu container)
Best Practices
Always include aria-checked attribute with a valid value
Use within a menu or menubar parent container
Provide visual indication of checked state (checkmark icon)
Support both Enter and Space key for toggling
Use tabindex="-1" and manage focus via arrow keys
Update aria-checked immediately when toggled
Use mixed state for parent items with partially selected children
Don't use for mutually exclusive options (use menuitemradio instead)
Don't place outside of a menu/menubar context
Don't forget to provide visible focus indicators
Don't rely only on color to indicate checked state
menuitemcheckbox vs menuitemradio
menuitemcheckbox
- Multiple items can be checked
- Supports mixed state
- Example: Bold, Italic, Underline
- Uses checkbox-style visual
menuitemradio
- Only one item can be selected
- No mixed state
- Example: Font size, Theme selection
- Uses radio-style visual
Common Use Cases
Bold, Italic, Underline, Strikethrough
Show/hide toolbars, sidebars, panels
Multiple category selection in filters
Batch file operations with select all
Toggle different notification types
Show/hide layers in design tools
Data table column toggles
Enable/disable multiple features
Accessibility Notes
Screen Reader Announcements
Screen readers announce menuitemcheckbox elements as "checkbox menu item" followed by the label and state. For example: "Bold, checkbox menu item, checked" or "Select All, checkbox menu item, mixed". The mixed state is announced as "partially checked" or "mixed" depending on the screen reader.
Focus Management
Individual menu items should have tabindex="-1" and focus should be managed programmatically using arrow keys. The currently focused item can use tabindex="0" for roving tabindex pattern. When the menu opens, focus should move to the first item.
Visual Indicators
Always provide clear visual indicators for each state. Use a checkmark (✓) for checked, an empty box for unchecked, and a horizontal line (−) or partially filled box for mixed. Ensure these indicators are not relying solely on color - use shape and icons as well.

