React hooks for implementing accessible button components with comprehensive keyboard, mouse, and touch interaction handling.
—
Quality
Pending
Does it follow best practices?
Impact
Pending
No eval scenarios have been run
Manages collections of toggle buttons with proper ARIA semantics, supporting both single and multiple selection modes. The group hooks provide container management and individual item behavior for toggle button collections.
Creates container behavior for toggle button groups with proper ARIA semantics.
/**
* Provides container behavior for toggle button groups with proper ARIA semantics
* and keyboard navigation support.
*/
function useToggleButtonGroup(
props: AriaToggleButtonGroupProps,
state: ToggleGroupState,
ref: RefObject<HTMLElement | null>
): ToggleButtonGroupAria;Creates behavior for individual items within a toggle button group.
/**
* Provides the behavior and accessibility implementation for a toggle button component
* within a toggle button group. Handles selection state coordination with the group.
*/
function useToggleButtonGroupItem(props: AriaToggleButtonGroupItemOptions<'button'>, state: ToggleGroupState, ref: RefObject<HTMLButtonElement | null>): ToggleButtonAria<ButtonHTMLAttributes<HTMLButtonElement>>;
function useToggleButtonGroupItem(props: AriaToggleButtonGroupItemOptions<'a'>, state: ToggleGroupState, ref: RefObject<HTMLAnchorElement | null>): ToggleButtonAria<AnchorHTMLAttributes<HTMLAnchorElement>>;
function useToggleButtonGroupItem(props: AriaToggleButtonGroupItemOptions<'div'>, state: ToggleGroupState, ref: RefObject<HTMLDivElement | null>): ToggleButtonAria<HTMLAttributes<HTMLDivElement>>;
function useToggleButtonGroupItem(props: AriaToggleButtonGroupItemOptions<'input'>, state: ToggleGroupState, ref: RefObject<HTMLInputElement | null>): ToggleButtonAria<InputHTMLAttributes<HTMLInputElement>>;
function useToggleButtonGroupItem(props: AriaToggleButtonGroupItemOptions<'span'>, state: ToggleGroupState, ref: RefObject<HTMLSpanElement | null>): ToggleButtonAria<HTMLAttributes<HTMLSpanElement>>;
function useToggleButtonGroupItem(props: AriaToggleButtonGroupItemOptions<ElementType>, state: ToggleGroupState, ref: RefObject<Element | null>): ToggleButtonAria<DOMAttributes>;Usage Examples:
import { useToggleButtonGroup, useToggleButtonGroupItem } from "@react-aria/button";
import { useToggleGroupState } from "@react-stately/toggle";
import { useRef } from "react";
// Basic toggle button group
function ToggleButtonGroup(props) {
let groupRef = useRef<HTMLDivElement | null>(null);
let state = useToggleGroupState(props);
let { groupProps } = useToggleButtonGroup(props, state, groupRef);
return (
<div {...groupProps} ref={groupRef}>
{props.children}
</div>
);
}
// Toggle button group item
function ToggleButtonGroupItem(props) {
let ref = useRef<HTMLButtonElement | null>(null);
let { buttonProps, isPressed, isSelected, isDisabled } = useToggleButtonGroupItem(
props,
props.state,
ref
);
return (
<button
{...buttonProps}
style={{
background: isPressed
? (isSelected ? 'darkblue' : 'gray')
: (isSelected ? 'blue' : 'lightgray'),
color: isSelected ? 'white' : 'black',
border: '1px solid #ccc',
padding: '8px 12px'
}}
ref={ref}>
{props.children}
</button>
);
}
// Complete toggle button group example
function TextAlignmentGroup() {
let groupRef = useRef<HTMLDivElement | null>(null);
let state = useToggleGroupState({
selectedKeys: ['center'],
selectionMode: 'single',
onChange: (selectedKeys) => {
console.log('Selected alignment:', [...selectedKeys]);
}
});
let { groupProps } = useToggleButtonGroup({
'aria-label': 'Text alignment',
orientation: 'horizontal'
}, state, groupRef);
return (
<div {...groupProps} ref={groupRef} style={{ display: 'flex', gap: 2 }}>
<ToggleButtonGroupItem id="left" state={state}>
Left
</ToggleButtonGroupItem>
<ToggleButtonGroupItem id="center" state={state}>
Center
</ToggleButtonGroupItem>
<ToggleButtonGroupItem id="right" state={state}>
Right
</ToggleButtonGroupItem>
</div>
);
}
// Multiple selection group
function FeatureToggles() {
let groupRef = useRef<HTMLDivElement | null>(null);
let state = useToggleGroupState({
selectedKeys: ['bold'],
selectionMode: 'multiple',
onChange: (selectedKeys) => {
console.log('Active features:', [...selectedKeys]);
}
});
let { groupProps } = useToggleButtonGroup({
'aria-label': 'Text formatting options'
}, state, groupRef);
return (
<div {...groupProps} ref={groupRef} style={{ display: 'flex', gap: 4 }}>
<ToggleButtonGroupItem id="bold" state={state}>
<strong>B</strong>
</ToggleButtonGroupItem>
<ToggleButtonGroupItem id="italic" state={state}>
<em>I</em>
</ToggleButtonGroupItem>
<ToggleButtonGroupItem id="underline" state={state}>
<u>U</u>
</ToggleButtonGroupItem>
</div>
);
}Configuration options for toggle button groups.
interface AriaToggleButtonGroupProps extends ToggleGroupProps, AriaLabelingProps {
/**
* The orientation of the toggle button group.
* @default 'horizontal'
*/
orientation?: Orientation;
/** Whether the toggle button group is disabled. */
isDisabled?: boolean;
}
interface ToggleGroupProps {
/** The currently selected keys in the collection (controlled). */
selectedKeys?: 'all' | Iterable<Key>;
/** The initial selected keys in the collection (uncontrolled). */
defaultSelectedKeys?: 'all' | Iterable<Key>;
/** Handler that is called when the selection changes. */
onChange?: (keys: Selection) => void;
/** The type of selection that is allowed in the collection. */
selectionMode?: SelectionMode;
/** Whether the collection allows empty selection. */
disallowEmptySelection?: boolean;
}
type SelectionMode = 'none' | 'single' | 'multiple';
type Selection = 'all' | Set<Key>;
type Orientation = 'horizontal' | 'vertical';Return value from the useToggleButtonGroup hook.
interface ToggleButtonGroupAria {
/**
* Props for the toggle button group container.
*/
groupProps: DOMAttributes;
}Configuration options for individual toggle button group items.
interface AriaToggleButtonGroupItemOptions<E extends ElementType> extends Omit<AriaToggleButtonGroupItemProps<E>, 'children'> {
/** An identifier for the item in the selectedKeys of a ToggleButtonGroup. */
id: Key;
/** The HTML element or React element used to render the button. @default 'button' */
elementType?: E | JSXElementConstructor<any>;
/** Whether the button is disabled. */
isDisabled?: boolean;
/** Handler that is called when the press is released over the target. */
onPress?: (e: PressEvent) => void;
/** Handler that is called when a press interaction starts. */
onPressStart?: (e: PressEvent) => void;
/** Handler that is called when a press interaction ends. */
onPressEnd?: (e: PressEvent) => void;
/** Handler that is called when the press state changes. */
onPressChange?: (isPressed: boolean) => void;
/** Handler that is called when a press is released over the target. */
onPressUp?: (e: PressEvent) => void;
/** Whether to prevent focus from moving to the button when pressing it. */
preventFocusOnPress?: boolean;
}State management interface for toggle button groups (from @react-stately/toggle).
interface ToggleGroupState {
/** The keys for the currently selected items. */
selectedKeys: Set<Key>;
/** Whether the collection allows empty selection. */
disallowEmptySelection: boolean;
/** The selection mode for the collection. */
selectionMode: SelectionMode;
/** Whether the collection is disabled. */
isDisabled: boolean;
/** Sets the selected keys. */
setSelected(key: Key, selected: boolean): void;
/** Toggles the selection state of an item. */
toggleKey(key: Key): void;
/** Replaces the selection with only the given key. */
selectKey(key: Key): void;
/** Selects all items in the collection. */
selectAll(): void;
/** Clears the selection. */
clearSelection(): void;
}Toggle button groups require state management via the useToggleGroupState hook from @react-stately/toggle:
import { useToggleGroupState } from "@react-stately/toggle";
// Single selection mode (radio group behavior)
let state = useToggleGroupState({
selectionMode: 'single',
selectedKeys: ['option1'],
onChange: (keys) => console.log('Selected:', [...keys])
});
// Multiple selection mode (checkbox group behavior)
let state = useToggleGroupState({
selectionMode: 'multiple',
selectedKeys: ['option1', 'option3'],
onChange: (keys) => console.log('Selected:', [...keys])
});
// No selection allowed
let state = useToggleGroupState({
selectionMode: 'none'
});aria-checked instead of aria-pressedaria-pressed for selection stateGroups support both horizontal and vertical orientations:
aria-orientation attributeuseToggleButtonGroup internally uses useToolbar from @react-aria/toolbar for:
Group items automatically coordinate with the group state:
Install with Tessl CLI
npx tessl i tessl/npm-react-aria--button