aria-pressed
Indicates the current "pressed" state of toggle buttons. Essential for creating accessible toggle buttons that communicate their on/off state to assistive technologies.
Overview
The aria-pressed attribute indicates the current "pressed" state of toggle buttons. When applied, screen readers announce the button as a "toggle button" and indicate whether it's currently pressed or not.
This attribute transforms a regular button into a toggle button. It supports three states: true (pressed), false (not pressed), and mixed (partially pressed, for tri-state toggles).
aria-pressed vs aria-checked
Use aria-pressed for toggle buttons. Use aria-checked for checkboxes, radio buttons, and switches. Don't mix them up!
Live Demo: Toggle Buttons
Text Formatting Toolbar
Status: Bold OFF | Italic OFF | Underline OFF
Simple Toggle Button
aria-pressed="false"
Tri-State Toggle (mixed state)
aria-pressed="mixed" • Click to cycle: mixed → true → false → mixed
Screen reader: "Bold, toggle button, not pressed" • "Mute Sound, toggle button, not pressed" • "Select All Items, toggle button, partially pressed"
Attribute Values
trueThe toggle button is currently pressed/activated. The feature or option it controls is turned on.
falseThe toggle button is not pressed. The feature or option it controls is turned off.
mixedThe toggle button is in a mixed state (neither fully pressed nor fully unpressed). Commonly used for "Select All" buttons when some but not all items are selected.
undefined(attribute absent)The button is NOT a toggle button. It's a regular action button. Do not set aria-pressed at all for non-toggle buttons.
Code Examples
Basic Usage
<!-- Basic aria-pressed usage -->
<!-- Toggle button - NOT pressed -->
<button
aria-pressed="false"
onclick="toggleMute(this)"
>
Mute Sound
</button>
<!-- Screen reader: "Mute Sound, toggle button, not pressed" -->
<!-- Toggle button - PRESSED -->
<button
aria-pressed="true"
onclick="toggleMute(this)"
>
Mute Sound
</button>
<!-- Screen reader: "Mute Sound, toggle button, pressed" -->
<script>
function toggleMute(button) {
const isPressed = button.getAttribute('aria-pressed') === 'true';
button.setAttribute('aria-pressed', !isPressed);
}
</script>Tri-State Toggle
<!-- Tri-state toggle button (true / false / mixed) -->
<!-- Parent "Select All" checkbox with mixed state -->
<button
aria-pressed="mixed"
aria-label="Select all items"
onclick="toggleSelectAll(this)"
>
<span class="checkbox-icon"></span>
Select All
</button>
<!-- Screen reader: "Select all items, toggle button, partially pressed" -->
<!-- Child items -->
<ul role="group" aria-label="Items">
<li>
<button aria-pressed="true">Item 1</button>
</li>
<li>
<button aria-pressed="false">Item 2</button>
</li>
<li>
<button aria-pressed="true">Item 3</button>
</li>
</ul>
<script>
function toggleSelectAll(button) {
const current = button.getAttribute('aria-pressed');
// Cycle: mixed -> true -> false -> mixed...
// Or: if mixed or false, select all (true)
// if true, deselect all (false)
const next = current === 'true' ? 'false' : 'true';
button.setAttribute('aria-pressed', next);
// Update child items
const items = document.querySelectorAll('[role="group"] button');
items.forEach(item => {
item.setAttribute('aria-pressed', next);
});
}
</script>Formatting Toolbar
<!-- Text formatting toolbar with toggle buttons -->
<div role="toolbar" aria-label="Text formatting">
<button
aria-pressed="false"
aria-label="Bold"
onclick="toggleFormat(this, 'bold')"
>
<strong>B</strong>
</button>
<button
aria-pressed="false"
aria-label="Italic"
onclick="toggleFormat(this, 'italic')"
>
<em>I</em>
</button>
<button
aria-pressed="false"
aria-label="Underline"
onclick="toggleFormat(this, 'underline')"
>
<u>U</u>
</button>
<button
aria-pressed="false"
aria-label="Strikethrough"
onclick="toggleFormat(this, 'strikethrough')"
>
<s>S</s>
</button>
</div>
<style>
/* Visual indication of pressed state */
button[aria-pressed="true"] {
background-color: #4f46e5;
color: white;
border-color: #4338ca;
}
button[aria-pressed="false"] {
background-color: white;
color: #374151;
border-color: #d1d5db;
}
</style>aria-pressed vs aria-checked
<!-- aria-pressed vs aria-checked - KEY DIFFERENCE -->
<!-- aria-pressed: For toggle BUTTONS -->
<button aria-pressed="true">
Dark Mode
</button>
<!-- Visual: Appears as a button
Semantic: This is a toggle button
Keyboard: Space or Enter to toggle -->
<!-- aria-checked: For checkbox/radio/switch ROLES -->
<div role="checkbox" aria-checked="true" tabindex="0">
Enable notifications
</div>
<!-- Visual: Appears as a checkbox
Semantic: This is a checkbox
Keyboard: Space to toggle (not Enter) -->
<!-- Switch using aria-checked (NOT aria-pressed) -->
<button role="switch" aria-checked="true">
Notifications
</button>
<!-- The switch role uses aria-checked, not aria-pressed -->
<!-- Rule of thumb:
• Buttons that toggle ON/OFF → aria-pressed
• Checkboxes, radios, switches → aria-checked
• Don't mix them up! -->React Component
// React Toggle Button Component
import { useState } from 'react';
function ToggleButton({
children,
defaultPressed = false,
onToggle,
...props
}) {
const [pressed, setPressed] = useState(defaultPressed);
const handleClick = () => {
const newState = !pressed;
setPressed(newState);
onToggle?.(newState);
};
return (
<button
{...props}
aria-pressed={pressed}
onClick={handleClick}
className={`toggle-button ${pressed ? 'pressed' : ''}`}
>
{children}
</button>
);
}
// Tri-state Toggle Button
function TriStateToggle({
children,
state, // true | false | 'mixed'
onToggle,
...props
}) {
const handleClick = () => {
// Cycle: mixed -> true -> false -> mixed
let newState;
if (state === 'mixed' || state === false) {
newState = true;
} else {
newState = false;
}
onToggle?.(newState);
};
return (
<button
{...props}
aria-pressed={state}
onClick={handleClick}
className={`toggle-button ${state === true ? 'pressed' : ''} ${state === 'mixed' ? 'mixed' : ''}`}
>
{children}
</button>
);
}
// Text Formatting Toolbar
function FormattingToolbar({ onFormatChange }) {
const [formats, setFormats] = useState({
bold: false,
italic: false,
underline: false,
});
const toggle = (format) => {
const newFormats = { ...formats, [format]: !formats[format] };
setFormats(newFormats);
onFormatChange?.(newFormats);
};
return (
<div role="toolbar" aria-label="Text formatting">
<ToggleButton
aria-label="Bold"
defaultPressed={formats.bold}
onToggle={() => toggle('bold')}
>
<strong>B</strong>
</ToggleButton>
<ToggleButton
aria-label="Italic"
defaultPressed={formats.italic}
onToggle={() => toggle('italic')}
>
<em>I</em>
</ToggleButton>
<ToggleButton
aria-label="Underline"
defaultPressed={formats.underline}
onToggle={() => toggle('underline')}
>
<u>U</u>
</ToggleButton>
</div>
);
}Best Practices
Always update aria-pressed value when the button is clicked
Provide clear visual indication of the pressed state (color, border, icon)
Use aria-pressed only on elements with button role or <button> elements
Consider using "mixed" for parent toggles when children have mixed states
Ensure the button label makes sense in both pressed and unpressed states
Don't use aria-pressed on checkboxes—use aria-checked instead
Don't use aria-pressed on switches—switches use aria-checked
Don't set aria-pressed on regular (non-toggle) buttons
Don't forget to style pressed state visually for sighted users

